works!
This commit is contained in:
parent
ba03c0921d
commit
b746ab36d6
@ -52,6 +52,7 @@ G_STMT_START { \
|
|||||||
extern gboolean vips__thread_profile;
|
extern gboolean vips__thread_profile;
|
||||||
|
|
||||||
void vips__thread_profile_attach( const char *thread_name );
|
void vips__thread_profile_attach( const char *thread_name );
|
||||||
|
void vips__thread_profile_detach( void );
|
||||||
void vips__thread_profile_stop( void );
|
void vips__thread_profile_stop( void );
|
||||||
|
|
||||||
void vips__thread_gate_start( const char *gate_name );
|
void vips__thread_gate_start( const char *gate_name );
|
||||||
|
@ -114,7 +114,6 @@ vips_thread_profile_save( VipsThreadProfile *profile, FILE *fp )
|
|||||||
g_mutex_unlock( vips__global_lock );
|
g_mutex_unlock( vips__global_lock );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_thread_profile_free( VipsThreadProfile *profile )
|
vips_thread_profile_free( VipsThreadProfile *profile )
|
||||||
{
|
{
|
||||||
@ -195,6 +194,21 @@ vips_thread_profile_get( void )
|
|||||||
return( g_private_get( vips_thread_profile_key ) );
|
return( g_private_get( vips_thread_profile_key ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This usually happens automatically when a thread shuts down, see
|
||||||
|
* vips__thread_profile_init() where we set a GDestroyNotify, but will not
|
||||||
|
* happen for the main thread.
|
||||||
|
*
|
||||||
|
* Shut down any stats on the main thread with this, see vips_shutdown()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vips__thread_profile_detach( void )
|
||||||
|
{
|
||||||
|
VipsThreadProfile *profile;
|
||||||
|
|
||||||
|
if( (profile = vips_thread_profile_get()) )
|
||||||
|
vips_thread_profile_free( profile );
|
||||||
|
}
|
||||||
|
|
||||||
static VipsThreadGate *
|
static VipsThreadGate *
|
||||||
vips_thread_gate_new( const char *gate_name )
|
vips_thread_gate_new( const char *gate_name )
|
||||||
{
|
{
|
||||||
|
@ -219,6 +219,9 @@ vips__init( const char *argv0 )
|
|||||||
g_set_prgname( prgname );
|
g_set_prgname( prgname );
|
||||||
g_free( prgname );
|
g_free( prgname );
|
||||||
|
|
||||||
|
vips__thread_profile_attach( "main" );
|
||||||
|
VIPS_GATE_START( "main" );
|
||||||
|
|
||||||
/* Try to discover our prefix.
|
/* Try to discover our prefix.
|
||||||
*/
|
*/
|
||||||
if( !(prefix = vips_guess_prefix( argv0, "VIPSHOME" )) ||
|
if( !(prefix = vips_guess_prefix( argv0, "VIPSHOME" )) ||
|
||||||
@ -374,7 +377,8 @@ vips_shutdown( void )
|
|||||||
|
|
||||||
im_close_plugins();
|
im_close_plugins();
|
||||||
|
|
||||||
vips__thread_profile_stop();
|
VIPS_GATE_STOP( "main" );
|
||||||
|
vips__thread_profile_detach();
|
||||||
|
|
||||||
/* In dev releases, always show leaks. But not more than once, it's
|
/* In dev releases, always show leaks. But not more than once, it's
|
||||||
* annoying.
|
* annoying.
|
||||||
|
@ -10,21 +10,19 @@ class ReadFile:
|
|||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.f = open(self.filename, 'r')
|
self.f = open(self.filename, 'r')
|
||||||
self.source = iter(self.f.readline, '')
|
|
||||||
self.lineno = 0
|
self.lineno = 0
|
||||||
self.getnext();
|
self.getnext();
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
self.f.close()
|
self.f.close()
|
||||||
return isinstance(value, StopIteration)
|
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
return self.line != ""
|
return self.line != ""
|
||||||
|
|
||||||
def getnext(self):
|
def getnext(self):
|
||||||
self.lineno += 1
|
self.lineno += 1
|
||||||
self.line = self.source.next()
|
self.line = self.f.readline()
|
||||||
|
|
||||||
def read_times(rf):
|
def read_times(rf):
|
||||||
times = []
|
times = []
|
||||||
@ -56,18 +54,29 @@ class Event:
|
|||||||
|
|
||||||
self.work = False
|
self.work = False
|
||||||
self.wait = False
|
self.wait = False
|
||||||
if re.match('.*: .*work.*', gate_name):
|
if re.match('.*?: .*work.*', gate_name):
|
||||||
self.work = True
|
self.work = True
|
||||||
if re.match('.*: .*wait.*', gate_name):
|
if re.match('.*?: .*wait.*', gate_name):
|
||||||
self.wait = True
|
self.wait = True
|
||||||
|
|
||||||
thread.events.append(self)
|
thread.events.append(self)
|
||||||
|
|
||||||
|
|
||||||
|
input_filename = 'vips-profile.txt'
|
||||||
|
|
||||||
thread_id = 0
|
thread_id = 0
|
||||||
threads = []
|
threads = []
|
||||||
n_events = 0
|
n_events = 0
|
||||||
with ReadFile('vips-profile.txt') as rf:
|
print 'reading from', input_filename
|
||||||
|
with ReadFile(input_filename) as rf:
|
||||||
while rf:
|
while rf:
|
||||||
|
if rf.line.rstrip() == "":
|
||||||
|
rf.getnext()
|
||||||
|
continue
|
||||||
|
if rf.line[0] == "#":
|
||||||
|
rf.getnext()
|
||||||
|
continue
|
||||||
|
|
||||||
match = re.match('thread: (.*)', rf.line)
|
match = re.match('thread: (.*)', rf.line)
|
||||||
if not match:
|
if not match:
|
||||||
print 'parse error line %d, expected "thread"' % rf.lineno
|
print 'parse error line %d, expected "thread"' % rf.lineno
|
||||||
@ -82,6 +91,9 @@ with ReadFile('vips-profile.txt') as rf:
|
|||||||
if not match:
|
if not match:
|
||||||
break
|
break
|
||||||
gate_name = match.group(1)
|
gate_name = match.group(1)
|
||||||
|
match = re.match('vips_(.*)', gate_name)
|
||||||
|
if match:
|
||||||
|
gate_name = match.group(1)
|
||||||
rf.getnext()
|
rf.getnext()
|
||||||
|
|
||||||
match = re.match('start:', rf.line)
|
match = re.match('start:', rf.line)
|
||||||
@ -145,58 +157,79 @@ def is_overlap(events, gate_name1, gate_name2):
|
|||||||
# allocate a y position for each gate
|
# allocate a y position for each gate
|
||||||
total_y = 0
|
total_y = 0
|
||||||
for thread in threads:
|
for thread in threads:
|
||||||
|
thread.total_y = total_y
|
||||||
|
|
||||||
y = 1
|
y = 1
|
||||||
gate_positions = {}
|
gate_positions = {}
|
||||||
for event in thread.events:
|
for event in thread.events:
|
||||||
if event.work or event.wait:
|
if event.work or event.wait:
|
||||||
gate_positions[event.gate_name] = 0
|
gate_positions[event.gate_name] = 0
|
||||||
elif not event.gate_name in gate_positions:
|
elif not event.gate_name in gate_positions:
|
||||||
overlap = True
|
no_overlap = False
|
||||||
for gate_name in gate_positions:
|
for gate_name in gate_positions:
|
||||||
if not is_overlap(thread.events, gate_name, event.gate_name):
|
if not is_overlap(thread.events, gate_name, event.gate_name):
|
||||||
gate_positions[event.gate_name] = gate_positions[gate_name]
|
gate_positions[event.gate_name] = gate_positions[gate_name]
|
||||||
overlap = False
|
no_overlap = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if overlap:
|
if not no_overlap:
|
||||||
gate_positions[event.gate_name] = y
|
gate_positions[event.gate_name] = y
|
||||||
y += 1
|
y += 1
|
||||||
|
|
||||||
event.y = gate_positions[event.gate_name]
|
event.y = gate_positions[event.gate_name]
|
||||||
event.total_y = total_y + y
|
event.total_y = total_y + event.y
|
||||||
|
|
||||||
total_y += y
|
total_y += y
|
||||||
|
|
||||||
PIXELS_PER_SECOND = 1000
|
PIXELS_PER_SECOND = 1000
|
||||||
PIXELS_PER_GATE = 20
|
PIXELS_PER_GATE = 20
|
||||||
WIDTH = int(last_time * PIXELS_PER_SECOND) + 100
|
LEFT_BORDER = 320
|
||||||
HEIGHT = int(total_y * PIXELS_PER_GATE) + 100
|
BAR_HEIGHT = 5
|
||||||
|
WIDTH = int(LEFT_BORDER + last_time * PIXELS_PER_SECOND)
|
||||||
|
HEIGHT = int((total_y + 1) * PIXELS_PER_GATE)
|
||||||
|
|
||||||
surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH + 50, HEIGHT)
|
||||||
ctx = cairo.Context (surface)
|
ctx = cairo.Context(surface)
|
||||||
|
ctx.select_font_face('Sans')
|
||||||
|
ctx.set_font_size(15)
|
||||||
|
|
||||||
ctx.scale (PIXELS_PER_SECOND, PIXELS_PER_GATE)
|
def draw_event(ctx, event):
|
||||||
|
left = event.start * PIXELS_PER_SECOND + LEFT_BORDER
|
||||||
|
top = event.total_y * PIXELS_PER_GATE
|
||||||
|
width = (event.stop - event.start) * PIXELS_PER_SECOND - 1
|
||||||
|
height = BAR_HEIGHT
|
||||||
|
|
||||||
|
ctx.rectangle(left, top, width, height)
|
||||||
|
|
||||||
|
if event.wait:
|
||||||
|
ctx.set_source_rgb(0.9, 0.1, 0.1)
|
||||||
|
elif event.work:
|
||||||
|
ctx.set_source_rgb(0.1, 0.9, 0.1)
|
||||||
|
else:
|
||||||
|
ctx.set_source_rgb(0.1, 0.1, 0.9)
|
||||||
|
|
||||||
|
ctx.fill()
|
||||||
|
|
||||||
|
if not event.wait and not event.work:
|
||||||
|
xbearing, ybearing, twidth, theight, xadvance, yadvance = \
|
||||||
|
ctx.text_extents(event.gate_name)
|
||||||
|
|
||||||
|
ctx.move_to(left + width / 2 - twidth / 2, top + theight)
|
||||||
|
ctx.set_source_rgb(1.00, 0.83, 0.00)
|
||||||
|
ctx.show_text(event.gate_name)
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
for thread in threads:
|
for thread in threads:
|
||||||
|
xbearing, ybearing, twidth, theight, xadvance, yadvance = \
|
||||||
|
ctx.text_extents(thread.thread_name)
|
||||||
|
ctx.move_to(0, theight + thread.total_y * PIXELS_PER_GATE)
|
||||||
|
ctx.set_source_rgb(1.00, 1.00, 1.00)
|
||||||
|
ctx.show_text(thread.thread_name)
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
for event in thread.events:
|
for event in thread.events:
|
||||||
ctx.move_to (event.start, event.total_y)
|
draw_event(ctx, event)
|
||||||
ctx.line_to (event.stop, event.total_y)
|
|
||||||
ctx.close_path ()
|
|
||||||
ctx.set_line_width (0.1)
|
|
||||||
|
|
||||||
if event.wait:
|
output_filename = "example.png"
|
||||||
ctx.set_source_rgb (0.9, 0.1, 0.1)
|
print 'writing to', output_filename
|
||||||
elif event.work:
|
surface.write_to_png(output_filename)
|
||||||
ctx.set_source_rgb (0.1, 0.9, 0.1)
|
|
||||||
else:
|
|
||||||
ctx.set_source_rgb (0.1, 0.1, 0.9)
|
|
||||||
|
|
||||||
ctx.stroke ()
|
|
||||||
|
|
||||||
ctx.select_font_face('Georgia')
|
|
||||||
ctx.set_font_size(0.9)
|
|
||||||
ctx.move_to(event.start, event.total_y + 0.5)
|
|
||||||
ctx.set_source_rgb(1, 1, 1)
|
|
||||||
ctx.show_text(event.gate_name)
|
|
||||||
|
|
||||||
surface.write_to_png ("example.png") # Output to PNG
|
|
||||||
|
Loading…
Reference in New Issue
Block a user