Monday, November 30, 2009

Using messages to notify events

Lately, i've been using frames extensively in my projects and recently i faced a little problem while working with them: how to notify the parent control (often a TForm) changes in the state of the frame controls/data?

I tried some approaches:

1) Add an event handler to the TDatasource.OnDataChange event.
This has the disadvantage of not being a generic solution since not always the frame has a TDataSource. Also this event is fired in changes to all fields of the respective TDataset, and often only a few fields need to be monitored, leading to some overhead. Yet is not possible to set the event at design time due to bug 14947.

2)Create handlers for events of child controls.
Works by setting in the parent form handlers for events, e.g. OnChange, of child controls of the frame. It has the drawback of needing more than one event handler in the case where is necessary to monitor more than one control/field.
Another problem is that such event handlers can be cleared by the IDE due to bug 14835. Not to say that sometimes the changes in the frame are not propagated to frame instances. In this case the workaround i found to sync the frames was to remove and add the frame again, loosing all properties set in the frame parent control.

So, i decided to implement a specific event for the frame. The first approach i thought was adding a TNotifyEvent property to the frame but this has almost the same drawbacks of approach 2. At this point the idea of using messages came in my mind.

AFAIK messages are used mostly in LCL and seldom in user projects so i had doubts if would work. Here is what i did:

1) Declare a custom message id constant
I declared the following constant in a shared unit:

LM_CHILDDATACHANGED = LM_USER + 1;
2) Create a method in the frame to send the message
I created a method SendDataChangeMsg with the following code:

var
Form: TCustomForm;
begin
Form := GetFirstParentForm(Self);
if Form <> nil then
Form.Perform(LM_CHILDDATACHANGED, 0, 0);
end;

The code is pretty straight. It get the parent form and then send the message through Perform method

3) Hook the events of the controls that should be monitored
Mostly OnChange events. Just called SendDataChangeMsg inside them

4) Add a property ValidData
This property checks if the data in the monitored controls are valid

5) Intercept the message at the frame parent (TForm)
In the TForm i put the frame, i created a method to intercept the message declared as follow:

procedure ChildDataChanged(var Msg: TLMessage); message
LM_CHILDDATACHANGED;


I'm using that to allow saving or not the data so i put a code to enable/disable the save button:

SaveButton.Enabled := Frame.ValidData;
That's all. It's working fine for me. In the end i got a pretty clear notify system. Now i can remove/add the frame as necessary without the need to reconnect the event handlers every time.



Sunday, November 15, 2009

Qt and Lazarus: a nice surprise (again)

Long, long time ago i wrote how the Lazarus Qt interface impressed me by its functionality. Yesterday, after updating my Lazarus working copy to do some debugging in Linux, i rebuilt the IDE as usual. But the IDE looked a little different, most notably the source editor font. I've got sometime to figure that the IDE was compiled using the Qt interface. I use the gtk2 interface but somehow i left the LCL build configured to Qt, so the unexpected result.

Again, the Qt interface surprised me. The IDE ran fine with good looking and very responsive except by bugs 15101 and 15103. Unfortunately, i use a lot the features that these bugs affect and i will stay with gtk2 for now. But as soon as these bugs are fixed i will give a try to Qt again.

Sunday, November 01, 2009

Using TDBEdit to handle date fields

If you try to link a date field with a TDBEdit, when an user inserts an invalid date, the control reacts with a non user friendly exception message. So, for long time, i used a TMaskEdit to edit date values and then update manually the dataset.
After some debate about TMaskEdit in the mail list i tried to workaround this problem.

The first think i did was to set the EditMask property to !99/99/9999;1;_ and hardcode the ShortDateFormat with a compatible format, e.g. 'dd/mm/yyyy'.

To validate the value inserted i created a handler to be linked to TDBEdit OnExit event(the color setting is optional):

var
D: TDateTime;
DateEdit: TDBEdit;
begin
DateEdit := Sender as TDBEdit;
if not TryStrToDate(DateEdit.Text, D) then
begin
ShowMessage(DateEdit.Text + ' is not a valid date');
DateEdit.Clear;
DateEdit.Color := clRed;
//or set a default value
//DateEdit.Text := '10/10/1900';
end
else
DateEdit.Color := clWindow;
end;

So you clear the TDBEdit and get a empty string that is valid value right? Not so fast. The message dialog will trigger an KillFocus message updating the Dataset with the old (and invalid) value. Calling ShowMessage after Clear does not help because the the control will try to update the dataset with " / / ", that is also not a valid value.

The solution i found was to handle the OnSetText event of the date field to skip all invalid values:

var
D: TDateTime;
begin
if not TryStrToDate(aText, D) then
Sender.Value := Null
else
Sender.AsDateTime := D;
end;

With this approach is possible to allow date edition with masks safely.

However, setting events for each TDBEdit and date field is annoying, so i created an TDBEdit descendant to handle this issue. It can be found in the LuiControls package (svn version).

In time:
  • Rx package has a TDBDateEdit component, but it does not allow editing with masks and don't manage invalid dates.
  • It's required a recent (post 0.9.28) svn version because of a bug in TMaskEdit in the earlier versions

Saturday, November 15, 2008

Effect of using a constant parameter for string types

Is not rare to find implementations of procedures/functions/methods that uses a value parameter for read only string arguments. While i always use constant parameters for such cases, the real benefit of this code practice was not clear. Until today.

I made a small application that implements two versions of a procedure identical except by the type of parameter (Value vs Constant)...

program asmConstParameter;

{$Mode ObjFpc}
{$H+}

uses
SysUtils, Types;

procedure DoIt(V: String);
begin
Writeln(V);
end;

procedure ByValue(V: String);
var
S: String;
begin
S := V;
DoIt(S);
end;

procedure ByReference(const V: String);
var
S: String;
begin
S := V;
DoIt(S);
end;

var
X: String;

begin
X := 'Test';
ByValue(X);
ByReference(X);
end.

...and examined the assembler output. See the difference yourself. Using optimizations through -O compiler options does not change the produced code.

So using a constant parameter has a practical effect, is not only a good code practice.

BTW: just for curiosity i put {$IMPLICITEXCEPTIONS OFF} in the program header. Not bad. Be aware that this info is here just for curiosity ;-) .

UPDATE: Using constant arguments also benefits ShortString types. See.

Sunday, October 26, 2008

Status of Virtual Treeview port

It has been more than one year after the last blog update about the Virtual Treeview (VTV) port and some people may be asking what happened with it.

The port is far from dead. In fact, it is fully working under Win32, Gtk1/2 and Qt since, at least, the previous six months. I was just waiting to the Lazarus 0.9.26 release to do an official release. Lazarus 0.9.26 is out, so where is the new VTV?

One of the main features of Lazarus 0.9.26 is the Unicode support for Win32 interface that, in your turn, uses UTF8 encoding. Currently VTV supports Unicode by using UTF-16/WideString and was working fine. After the LCL Unicode switch some encoding conversion problems appeared when iterating with strings returned by databases or LCL controls, so i decided to anticipate the migration to UTF-8 before doing a release.

This task is not trivial and i'll start to work on it only after December, so don't expect an release soon.

This has some advantages:
  • There will be no need to further string types changes (WideString -> String) in applications created with the released component
  • It will be faster since WideString is known to be slower specially under Win32
Anyway if someone is interested in testing the component check the instructions on how to use the svn version here. Be aware that a change from WideString to String type will be necessary in the long run.

Sunday, June 01, 2008

LCL, Gtk2, Pango and Cairo

Introduction

Lately, in the Lazarus mail list, has been a lot of discussion about the performance of LCL/TextOut under Gtk2 and many (erroneous) arguments used derives from the lack of proper knowledge, including from myself. So in this article, i'll try to clear the things a bit.

When Gtk2 was released back in 2002, Pango was one of the Gtk2 main new features. Pango provides support to render Unicode text (encoded in utf8) with advanced layouts. But i was also one of the reasons of the degraded performance of Gtk2 when compared with its predecessor.

Pango has a flexible design allowing to use different backends (Cairo, Xft, Win32, X) to render text. Until version 2.6 Gtk2 used the Xft backend that was replaced, starting from version 2.8, by cairo (a 2D vector drawing library) as the default renderer. At that time the performance dropped even more, but after some work in pango and in cairo, the things got better.

So, the first point to take in consideration when evaluating pango performance is the version of pango and cairo. More on this later.

Testing LCL

In order to get an accurate diagnostic, i wrote an test application that fills an entire window with text using TextOut and compared the results (output quality and time to draw) of the Linux widgetsets (Gtk1, Gtk2, Qt).

Here is the output:




The time to draw an entire screen (average times of 15 iterations):

gtk1: 24ms
gtk2: 150ms
qt: 92ms

The gtk1 widgetset is really fast but it has two drawbacks: the font quality is low and the screen flickers while updating.
The gtk2 widgetset is the slowest loosing to qt by 60%, but in other hand has the sharpest font draw. An important point is that when double buffer is disabled (LCL disables it by default), the screen flickers just like gtk1, but if double buffer is enabled there's no flicker and the screen is updated instantaneous.
The qt widgetset is in the midterm both in quality and in speed. Not sure why qt text looks blurred: if is a configuration or the default font is not so good. There's also no screen flicker since qt is all double buffered.

Gtk2 dissected (almost)

Pango allows more than one engine to be used and there's also the options to draw directly using cairo or the old gdk functions (that use the X11 bitmap fonts). So i wrote an application using direct calls to the gtk2 api. It draws text with default Gtk2 (Pango/Gdk), Pango/Xft, Xft, Cairo, Gdk/X11.

The output (Cairo is equal to Gtk2 and Gdk/X11 is equal to LCL/Gtk1):



The time results:

Gtk2 (Pango/Gdk): 130ms
Cairo: 90ms
Xft: 70ms
Gdk/X11: 12ms
Pango/Xft: 110ms

Gtk2: very close to LCL/Gtk2
Cairo: the same quality of Pango/Gdk (I would be very surprised if was different ;-)) but significantly faster
Xft: Almost two time faster then Pango/Gdk but with lower quality output (An configuration issue?)
Gdk/X11: basically the same output of gtk1. Again really faster but without the screen flicker of gtk1.
Pango/Xft: faster than Pango/Gdk, slower than Xft. Out of option since is not working at all: it draws always at 0,0 coordinates.

Alternatives to pango?

From this tests, using directly Cairo to draw text seems to be a good option to replace Pango: the same quality and faster. But is not that easy. With direct calls to Cairo is needed to do all sort of text position (bidi, alignment) and text styles (underline) manually. Also it would be necessary to do the font selection and loading logic manually in a system specific way,i.e., is necessary different code to Linux/Win32/MacOSX.

Another option is using Xft directly. Aside from the different/worse output, it would be necessary to change the widgetset to retrieve the XftDraw handle for each drawable which is a complex task principally for double buffered controls. All in a system specific way.

Gdk/X11: the quality of output and lack of Unicode support makes a no-no option. At least for me.

Conclusion

Is there a direct/easy/faster replacement for Pango under LCL/Gtk2? No.

Here is necessary to make another question: there's a real need to replace it? Like shown earlier, default Pango is really slow compared to other alternatives, but, principally when double buffer is enabled, there's no visible glitches or general system slowdown. Is also necessary to take in account the increase of code size and complexity in LCL/Gtk2 side to make such change.

Notes

  • The test applications can be found here and here. Is necessary the package chronolog;
  • The test were conducted in a Celeron 1.4, 512MB, with an intel integrated video running Ubuntu 8.04;
  • Upgrading from Ubuntu 7.10 to 8.04 leaded to an significant speed in all widgetsets (Gtk2 250 > 150 / Gtk1 50 > 24ms);
  • I also tested drawing with low level Pango api. I'll post the results later;
  • Win32 took impressive 5ms in the same test Not to be considered since the win32 test was done in another (more powerful) machine;
  • A point that is not directly related to text draw but affects performance of LCL/Gtk2 is the fact that the LCL/Gtk2 test application calls 4 times FcFontSort, while a Gtk2 pure application calls only once. This is an expensive call that takes almost 20% of the application time.

Saturday, March 15, 2008

Reduce memory usage of LCL

To test the conclusions of the last post i modified the field order of some LCL classes to group together Boolean fields.

Here's the return value of the InstanceSize property:

TButton
before: 874 bytes
after: 829 bytes (saved 24, 16 and 5 bytes in TControl, TWinControl and TCustomButton respectively)

TMenuItem
before: 152 bytes
after: 136 bytes

In an application with 100 controls and 20 menu items you save 2400 (considering only TControl memory) and 320 bytes respectively.

Maybe be this is negligible in computers with 1GB or more of RAM, but for mobile platforms it makes a difference.

The patch is here. Have fun!

Tuesday, February 19, 2008

Memory layout (and size) of a object

After reading a article about memory layout of objects in Delphi i was curious about how fpc behaves. So i did some small tests:

Memory layout of objects (instances of a class)

At offset 0 resides the virtual method table. Starting from ofsset 4 comes the fields. Just like in Delphi.

Number of associated methods

The number of associated methods and if they are virtual does not influence the object size. Just like in Delphi.

Type of the fields

According to the cited article, Delphi reserves 4 bytes for each field even if the type has a size of 1 byte. Here comes the fun.

Take the following classes:

TOneFlagClass = class
Flag1: Boolean;
end;

TTwoFlagClass = class
Flag1: Boolean;
Flag2: Boolean;
end;

The size of TOneFlagClass and TTwoFlagClass are 5 and 6 bytes respectively (4 for the vmt and 1 for each field). The memory offsets of Flag1 and Flag2 are 4 and 5.

Delphi is a bit different here. The size of both classes are 8. The memory offsets of the fields are the same as fpc.

At this time i think: "In this case is better to place less than 4 bytes fields at the end of the class declaration to avoid subsequent fields to be accessed outside the dword boundary"

I was wrong. In fact half wrong:

Take the following classes:
TFlagFirstClass = class
Flag1: Boolean;
Int1: Integer;
end;

TFlagLastClass = class
Int1: Integer;
Flag1: Boolean;
end;
The size of TFlagFirstClass and TFlagLastClass are 12 and 9 respectively. The compiler allocates 4 bytes for the boolean field to maintain subsequent fields (that has a size of 4 bytes) aligned with the dword boundary.

If another boolean field (Flag2) is added just after Flag1, the instance size is not affected. In fact, grouping 4 boolean (or another 1 byte type) fields together will lead to the same instance size as only one boolean field if those are succeeded by Integer or Pointer like types.

In the end, my suggestion is still valid: put the "less than 4 bytes field types" at the end of the field declaration of the class (or group together in groups with 4 bytes in total). You will save some memory.

If you are not convinced compare size of a class with the following fields sequence:
Boolean, Integer, Boolean, Integer, Boolean, Integer, Boolean, Integer
Boolean, Boolean, Boolean, Boolean, Integer, Integer, Integer, Integer
Integer, Integer, Integer, Integer, Boolean, Boolean, Boolean, Boolean

Some notes:
  • Object here is not referenced as the object type (that has the same memory layout of a record), but as the instance of a class
  • There's no difference between mode delphi and objfpc
  • It's valid only for i386 architeture. No idea how this works in ppc, amd64, arm

Wednesday, January 23, 2008

Effect of buffer size in deflate and md5

I tested the effect of buffer size in compressing a file using deflate procedure (paszlib unit) and calculating the md5 (using the functions of md5 unit).

I loaded a 30MB file in memory and did the compression/md5 calculation. The buffer size varied from 1024 to 512.000.

To my surprise no significantly difference was found, so no graph this time since is almost a plain line.

Friday, October 26, 2007

What Time Is It?

How many cairo clocks the world needs?

I don't think we have sufficient!


Monday, October 15, 2007

Effect of buffer size for reading files [Linux]

Reading a file entirely in memory is not a good idea as stated before, but how large should be the memory buffer?

I did a test under Linux (Ubuntu 7.04) reading the fpc2.2.0 installation file (29MB) using different buffer sizes.

Here's the result:


The time to read the file decreases as the buffer size increases until the buffer is 128kb then, as the buffer gets bigger, the trend inverts.

Some notes:
  • The test was executed three times for each buffer size. The results are expressed as the Median;
  • The Y axis is the time to read all the file in microseconds. The X axis is the buffer size in bytes;
  • The first time the file is read is significantly slower than subsequent reads. Probably this is an effect of the OS file system buffering (I did not find a way to skip it). This limits further analysis. However, excluding the first run, all other results are consistent across the same buffer size. All results can be browsed here.

Monday, October 01, 2007

Strange days...

Since day 1 of Lazarus, the gtk1 widgetset is the default, and reference, interface under Linux.

Today, after one of my applications crashed using gtk1, i tried it with the Qt4 interface: it worked flawlessly!!.

The Qt interface, given the recent work, is in the way to become the standard widgetset under Linux. Wait and see.

Tuesday, September 25, 2007

Update: Using Valgrind/massif with fpc

In a previous post i claimed that the option to hide memory allocation wrappers in massif was broken or not working with fpc.

The problem is that i was using only the pascal name of the function (CMEM_CGETMEM) instead of the mangled internal name (CMEM_CGETMEM$LONGINT$$POINTER).

Thanks to Michalis Kamburelis that gave the hint and also provided this script:

#!/bin/sh
set -eu

valgrind --tool=massif \
--alloc-fn='CMEM_CGETMEM$LONGINT$$POINTER' \
--alloc-fn='CMEM_CREALLOCMEM$POINTER$LONGINT$$POINTER' \
--alloc-fn='SYSTEM_GETMEM$LONGINT$$POINTER' \
--alloc-fn='SYSTEM_GETMEM$POINTER$LONGINT' \
--alloc-fn='SYSTEM_REALLOCMEM$POINTER$LONGINT$$POINTER' \
--format=html \
"$@"
I updated the previous charts so they show where in pascal code the memory is allocated.

PS: it's annoying that the function names are truncated in the charts.

Sunday, September 23, 2007

Zlibar memory behavior compressing many small files

The previous analysis of zlibar memory behavior was done taking as example the compression of one big file. Let's with many small files (all *.pas files under lazarus/lcl dir).

Original (load the entire file in memory):
The heaptrc dump:
18573 memory blocks allocated : 496119560/496173048
18573 memory blocks freed : 496119560/496173048
0 unfreed memory blocks : 0
True heap size : 4423680
True free heap : 4423680


After memory optimization (load file in small buffer):
The heaptrc dump:
17446 memory blocks allocated : 439659064/439708048
17446 memory blocks freed : 439659064/439708048
0 unfreed memory blocks : 0
True heap size : 2326528
True free heap : 2326528



We can take some conclusions:
  • The memory usage is almost equal over time (the graph scale does not help much here)
    UPDATE: the heaptrc dump shows that the original code really takes more memory.
  • In the optimized build the memory is allocated in a continuous fashion, always growing. The original build the memory is allocated and freed all over time while still growing in the end. This can lead to more memory fragmentation.
  • In the optimized build there's not the final peak. This is not really expected since the section of code responsible by the peak was not changed. Some options: 1) the peak exists but valgrind does not detect 2) a bug in the optimized code 3) an unexpected (and good) side effect

Reduce zlibar memory usage - step1

Previously we learned that zlibar uses 1.5MB of memory to compress a 1.1MB file. It compress each file in three passes: 1) loads all the file into memory 2) feed the deflate function with this data using a small buffer as a bridge 3) calculate the md5 signature transversing the file data again.

The option is to compress using only one pass: load the file data incrementally into a memory buffer and than feed deflate and md5 functions with it. It has two advantages: the memory usage (in this step) is constrained by the size of the buffer and you save the memory copy from the stream (that holds the file data) to the deflate buffer and to md5 buffer.

The modified InternalCompressStream function would be something like:

MD5Init(Context);
z.next_in := @input_buffer;
z.avail_in := FileRead(InStream, input_buffer, MAX_IN_BUF_SIZE);
MD5Update(Context, input_buffer, z.avail_in);
while z.avail_in > 0 do
begin
repeat
z.next_out := @output_buffer;
z.avail_out := MAX_OUT_BUF_SIZE;
err := deflate(z, Z_NO_FLUSH);
OutStream.Write(output_buffer, MAX_OUT_BUF_SIZE - z.avail_out);
until Z.avail_out > 0;
z.next_in := @input_buffer;
z.avail_in := FileRead(InStream, input_buffer, MAX_IN_BUF_SIZE);
MD5Update(Context, input_buffer, z.avail_in);
end;
MD5Final(Context, Result.Md5Sum);

Lets run valgrind/massif to see what we got:

Comparing with the previous graph we notice a great memory usage reduction: from 1.5MB to 0.5MB.

The heaptrc dump:
55 memory blocks allocated : 2811961/2812056
55 memory blocks freed : 2811961/2812056
0 unfreed memory blocks : 0
True heap size : 950272
True free heap : 950272

Let's do a deeper analysis:
  • The memory used by deflate functions is close to the expected 256kb.
  • The pink area is the memory used by the stream that holds the compressed data. It is allocated incrementally so the ascending angle.
  • There's a peak after the deflate memory is freed and just before the program finishes. This represents the copy from the compressed stream to the output stream that doubles the data in memory. More on this later.
Someone may say that load a file using a small buffer is slower than reading all data directly in memory. This is true but it would be reasonable only with small files. In a general usage packer it would be a big limitation.

Tuesday, September 18, 2007

Using Valgrind to profile fpc applications

Before starting to optimize is necessary to know beforehand what and where to optimize. It's here that the profiler tools plays a role. Valgrind, and its brother KCachegrind, are know unix profiler tools that makes success in the C crowd. Let's see if is useful to fpc programmers.

Zlibar is a fpc component that encapsulates the paszlib functions in a programmer friendly way. I use it in the Becape application and for sometime i have a plan to optimize it.

The heart of the component is the TZlibWriteArchive.CreateArchive method that compress the files (InputFiles) into a stream (OutputStream):

TmpStream := TMemoryStream.Create;
TmpFile := TMemoryStream.Create;
[..]
for X := 0 to fInputFiles.Count-1 do begin
[..]
TmpFile.LoadFromFile(fInputFiles.FileName[X]);
[..]
FileInfo.CompressedSize := InternalCompressStream(X, TmpFile, TmpStream); //(1)
FileInfo.Md5Sum := StreamMD5(TmpFile);
[..]
end;
WriteHeader(AHeader);
OutStream.CopyFrom(TmpStream, TmpStream.Size);//(2)
[..]


It creates two temporary memory streams (TmpFile and TmpStream). TmpFile will hold the uncompressed data of the file being added. TmpStream will be filled with the compressed data in step (1). The process continues until all files are compressed in the TmpStream.
After that the header is written in the OutputStream and then the compressed data is written in the OutputStream.

The problems:
  1. The file is stored entirely in memory before is processed. For small files is fine but for larger files it would be problems.
  2. Even for small files the memory of TmpFile will be reallocated in most of the LoadFromFile calls
  3. After step (2), you will have three streams in the heap: an uncompressed file, the compressed data of all files and a header + the compressed data of all files
To see this in action i created a small application that just compress only file (the VirtualTrees.pas with 1.1MB), and compiled with -gv (Generate code for Valgrind) and -gl. Run with valgrind(callgrind):

valgrind --tool=callgrind ./zlibar_opt
It was created a file with the pattern callgrind.out.[pid] that i loaded in KCacheGrind. In this tool is possible to see most of the function calls the application did, the times that each function were called, who called who, and the time each function spent.
To my surprise the memory allocation routines does not spent much time (in fact was zero). The most expensive was, of course, the compression related functions.





Now let's use the massif tool:

valgrind --tool=massif ./zlibar_opt
It creates two files: massif.[pid].ps and massif.[pid].txt. The txt file contains info about the callstack and how much memory each function allocated. The ps file contains a graphic showing the functions that were responsible for most memory allocation and the evolution in time. See below:


Now you say "what hell is this"?
To work with valgrind the -gv option forces the use of the cmem memory manager which is a wrapper around malloc, so massif understand the cmem* functions as the programmers allocation routines. I tried to use the fn-alloc option to force the display of the pascal functions without success.

Update: i was passing only the pascal name function (CMEM_GETMEM) to fn-alloc while is necessary also the parameter list names. I updated the charts to show where in pascal the memory is allocated.

Anyway in the graphic we can see that 1.5MB of heap memory is allocated (used?*) at its peak and that is the point where we can optimize.

Here's the heaptrc dump:
58 memory blocks allocated : 3926105/3926208
58 memory blocks freed : 3926105/3926208
0 unfreed memory blocks : 0
True heap size : 950272
True free heap : 950272

In the next articles, i will take a look in the possible optimizations.

Notes:
  • * The fpc heap manager pre allocates space in the heap that sometimes is not all used but i dont know if this is still valid when using the cmem functions
  • The -gv option is necessary to run the massif tool but is dispensable when using the callgrind
  • The valgrind checkmem tool is of little utility to fpc since it provides the heaptrc unit with a lot of advantages
  • One drawback of valgrind is that is exclusive to unix. No windows.
  • For more info see the valgrind manual

Back to blogging and to lower levels

This blog has been quiet lately, but is not dead.

In the last months a played a lot with LCL, sometimes in the VirtualTreeView port, sometimes writing original components. I will take a rest in high level/GUI programming and return to lower levels.

Starting from today i will post a sequence of articles about memory usage and general optimizations to fpc/Lazarus applications.

Later, i plan to talk about file system integration and IPC techniques.

Thursday, March 15, 2007

... and not alone!

After getting VTV to work reasonably well under Windows, i started to port it to Linux/gtk.

It's already compiling but crashes at start with the following message:

"BadMatch (invalid parameter attributes)"

Searching such message in Google i get 32.800 results.

At least, i'm not alone ;-)

Not so far ...

Before than i think i got VTV to work under Windows (In fact is working since, at least, two weeks).

Is almost everything there: Header, OLE drag and drop (and VCL too), Unicode, Bidi. Alpha Blend is still missing. There are also some graphic glitches with the more advanced examples.

Here's a sample:

Thursday, February 15, 2007

Traps of Delphi to Lazarus conversion

There's only a thing worse than a bug difficult to resolve: a bug difficult to find. As an example, i was getting a weird bug in the drawing of VTV. The colors were being painted wrongly and only after a few hours i figured what was going on. See the code below:

with Canvas do
begin
[..]
Brush.Color:=Color;
[..]
end;


Apparently nothing wrong. But the Devil resides in the details. Under Delphi there's no TCanvas.Color while there's in LCL. The result of this code, in Delphi, is that Brush.Color is assigned to TControl.Color. In LCL, Brush.Color is assigned to TCanvas.Color (which in your turn points back to Brush.Color!!).

You can't even say that there's a bug in LCL or in the program. Is just one of traps found while converting Delphi code.

The same occurs with TCanvas.Width/Height (does not exist in Delphi) and TBitmap.Width/Height when used inside compound "with" statements.