Schrift
[thread]5037[/thread]

Tk::Font::measure ist zu langsam

Leser: 3


<< >> 10 Einträge, 1 Seite
betterworld
 2005-07-24 17:03
#44243 #44243
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
Hallo.

Ich moechte mit Tk einen HTML-Renderer schreiben, und dazu wollte ich von jedem einzelnen Wort die Breite (abhängig von der Schriftart) bestimmen.

In der Doku habe ich dazu die Funktion "measure" in Tk::Font gefunden. Nun habe ich aber widerfahren müssen, dass sie verdammt langsam ist. Und was mich sehr wundert, ist:
1) Es dauert zwar sehr lange, viele Worte auszumessen, aber das Zeichnen der Wörter in ein Canvas passiert fast instantan, also schnell.
2) Auch dauert es nicht lange, wenn man statt der einzelnen Woerter die Verkettung ausmisst.
3) esskar sagt, auf Windows geht es schneller... (ich habe Linux, und einen amd600)

Hier ist ein Script, das das Problem illustriert:
Code: (dl )
1
2
3
4
5
use Tk;
use Tk::Font;
my $w=MainWindow->new;
my $f=$w->Font;
$f->measure("hallo") for 0..399
Für diese 400 Mal rendern brauche ich ca. eine halbe Minute.

Hier ein Beispiel zu Punkt (2) oben:
Code: (dl )
1
2
3
4
5
use Tk;
use Tk::Font;
$w=MainWindow->new;
$f=$w->Font;
$f->measure("hallo" x 400)
(Sekundenbruchteil)

Weiß jemand eine Erklärung, oder sogar eine bessere Lösung?
Ich habe überlegt, alle Buchstaben einzeln auszumessen und die Ergebnisse zu speichern, aber das ist unschön und könnte Probleme mit Kerning geben.

Noch eine Frage: Warum braucht man ein Widget, um eine Font zu erzeugen oder auszumessen?

Danke.\n\n

<!--EDIT|betterworld|1122211071-->
lichtkind
 2005-07-24 19:58
#44244 #44244
User since
2004-03-22
5697 Artikel
ModeratorIn + EditorIn
[Homepage]
user image
notorious disclaimer: in Wx ist schon ein HTML-Widget dabei
Wiki:Tutorien in der Wiki, mein zeug:
kephra, baumhaus, garten, gezwitscher

Es beginnt immer mit einer Entscheidung.
esskar
 2005-07-24 20:41
#44245 #44245
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
[quote=lichtkind,24.07.2005, 17:58]notorious disclaimer: in Wx ist schon ein HTML-Widget dabei[/quote]
gibts auch für Tk; aber manchmal ist ganz schön, ein paar sachen selbst zu tun
ptk
 2005-07-25 12:35
#44246 #44246
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Seltsam. Es macht auch keinen Unterschied, ob man Tk800 oder Tk804 verwendet. Es geht auch viel schneller, wenn man den Text in einem Canvas rendert und die Bounding Box ausrechnet. Ansonsten: wenn du wordwrapping selbst implementieren willst, dann lohnt sich wahrscheinlich eine binäre Suche nach den Zeilengrenzen. Vielleicht wuerde es auch helfen, wenn man erst einmal einen Hash mit allen Buchstabenbreiten erzeugt und damit arbeitet (was aber wegen moeglichen Kernings nicht perfekt waere).
esskar
 2005-07-25 13:35
#44247 #44247
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
habs mal nochmal genau gemacht!

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use strict;
use warnings;

use Benchmark qw(:all);
use Tk;
use Tk::Font;

my $w=MainWindow->new;
my $f=$w->Font;

sub time_font_measure {
$f->measure("hallo");
}

timethis(   10, \&time_font_measure);
timethis(  100, \&time_font_measure);
timethis(  400, \&time_font_measure);
timethis( 1000, \&time_font_measure);
timethis(10000, \&time_font_measure);


timethis 10:  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)
           (warning: too few iterations for a reliable count)
timethis 100:  0 wallclock secs ( 0.00 usr +  0.02 sys =  0.02 CPU) @ 6250.00/s (n=100)
           (warning: too few iterations for a reliable count)
timethis 400:  0 wallclock secs ( 0.05 usr +  0.02 sys =  0.06 CPU) @ 6349.21/s (n=400)
           (warning: too few iterations for a reliable count)
timethis 1000:  0 wallclock secs ( 0.13 usr +  0.05 sys =  0.17 CPU) @ 5813.95/s (n=1000)
           (warning: too few iterations for a reliable count)
timethis 10000:  2 wallclock secs ( 1.02 usr +  0.61 sys =  1.63 CPU) @ 6153.85/s (n=10000)
ptk
 2005-07-25 16:19
#44248 #44248
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Windows, nehme ich an? Unter Linux (perl 5.8.0, Tk 800.025, X 4.2.0) ist es:
Code: (dl )
1
2
3
4
5
timethis 10:  0 wallclock secs ( 0.10 usr +  0.01 sys =  0.11 CPU) @ 90.91/s (n=10)
(warning: too few iterations for a reliable count)
timethis 100: 4 wallclock secs ( 1.05 usr + 0.11 sys = 1.16 CPU) @ 86.21/s (n=100)
timethis 400: 17 wallclock secs ( 4.09 usr + 0.16 sys = 4.25 CPU) @ 94.12/s (n=400)
timethis 1000: 45 wallclock secs (10.64 usr + 0.54 sys = 11.18 CPU) @ 89.45/s (n=1000)
(Und danach wurde es mir zu langweilig...)
ptk
 2005-07-25 16:21
#44249 #44249
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
... und xfs scheint sehr beschaeftigt zu sein und der perl-Prozess holt sich jedesmal die gesamte Fontliste ab. Hmmm.
ptk
 2005-07-25 16:23
#44250 #44250
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Wenn ich explizit einen Font angeben, sieht es auch unter Linux viel freundlicher aus.
Code: (dl )
my $f=$w->Font(family => "helvetica", size => 10);

Code: (dl )
1
2
3
4
5
6
7
8
timethis 10:  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)
(warning: too few iterations for a reliable count)
timethis 100: 0 wallclock secs ( 0.06 usr + 0.00 sys = 0.06 CPU) @ 1666.67/s (n=100)
(warning: too few iterations for a reliable count)
timethis 400: 1 wallclock secs ( 0.26 usr + 0.01 sys = 0.27 CPU) @ 1481.48/s (n=400)
(warning: too few iterations for a reliable count)
timethis 1000: 2 wallclock secs ( 0.77 usr + 0.03 sys = 0.80 CPU) @ 1250.00/s (n=1000)
timethis 10000: 19 wallclock secs ( 6.81 usr + 0.41 sys = 7.22 CPU) @ 1385.04/s (n=10000)


Nachtrag:
Des Raetsels Loesung: wenn kein expliziter Fontname angegeben wurde, schickt Tk jedesmal eine Anfrage fuer den Font mit dem Namen -*-*-*-*-*-*-*-*-*-*-*-. Dadurch bekommt er erst einmal die gesamte Fontliste zurueck (die normalerwese einige 100K gross ist) und waehlt erst einmal den richtigen Font aus.\n\n

<!--EDIT|ptk|1122294358-->
esskar
 2005-07-25 16:28
#44251 #44251
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
[quote=ptk,25.07.2005, 14:23]Nachtrag:
Des Raetsels Loesung: wenn kein expliziter Fontname angegeben wurde, schickt Tk jedesmal eine Anfrage fuer den Font mit dem Namen -*-*-*-*-*-*-*-*-*-*-*-. Dadurch bekommt er erst einmal die gesamte Fontliste zurueck (die normalerwese einige 100K gross ist) und waehlt erst einmal den richtigen Font aus.[/quote]
sehr ungeschickt;
ich denke, windows schickt dann den default-font (falls es überhaupt in dieser weise unter windows so implementiert wurde)
betterworld
 2005-07-25 20:08
#44252 #44252
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
Danke fuer die Antworten.

Die Erklärung mit xfs klingt einleuchtend. (Auch wenn ich keinen xfs verwende, aber trotzdem bezieht Tk jedes Mal die Font vom X-Server, wie ich gerade mit strace herausgefunden habe.) Es scheint noch etwas mehr dahinterzustecken. Gerade habe ich, angeregt durch ptks Beispiel, herausgefunden, dass es weitaus länger dauert, wenn man Helvetica groß schreibt, als wenn man es klein schreibt. Hier eine Demonstration:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Benchmark (':all');
use Tk;
use Tk::Font;
my $mw = MainWindow->new;
my $f1 = $mw->Font(-family => 'helvetica', -size => 10 );
my $f2 = $mw->Font(-family => 'Helvetica', -size => 10 );
timethese( $_, {
'klein' => sub { $f1->measure('hallo'); },
'groß' => sub { $f2->measure('hallo'); },
}) for 400, 1000;

# Ausgabe:
Benchmark: timing 400 iterations of groß, klein...
groß: 28 wallclock secs (19.58 usr + 0.33 sys = 19.91 CPU) @ 20.09/s (n=400)
klein: 14 wallclock secs ( 7.44 usr + 0.21 sys = 7.65 CPU) @ 52.29/s (n=400)
Benchmark: timing 1000 iterations of groß, klein...
groß: 69 wallclock secs (48.47 usr + 0.65 sys = 49.12 CPU) @ 20.36/s (n=1000)
klein: 39 wallclock secs (18.70 usr + 0.49 sys = 19.19 CPU) @ 52.11/s (n=1000)


Ich hatte eigentlich gedacht, dass beim Erzeugen der Font der X-Server kontaktiert wird, und sie anschließend gecacht wird. Das wäre effizienter.

Die Idee mit der binären Suche von ptk klingt interessant. Das wird wahrscheinlich auch bessere Resultate für (kursive) Buchstaben ergeben, die über den Wortrand herausragen. Ich merk mir das mal für später.

Vielleicht werde ich zum Ausmessen der Schriften einfach andere Module (wie Font::AFM, was ich gerade bei CPAN entdeckt habe) benutzen, und nur das Zeichnen dann Tk überlassen.\n\n

<!--EDIT|betterworld|1122307788-->
<< >> 10 Einträge, 1 Seite



View all threads created 2005-07-24 17:03.