Construct a ZoneRange processing events from a range of Events (e.g. EventRange).
Are there no more zones?
Get the current zone.
Go to the next zone.
Get a copy of the range in its current state.
ForwardRange of ZoneData ordered by end time. Doesn't allocate any heap memory.
If profile data is incomplete (e.g. because the Profiler ran out of assigned memory in the middle of profiling), zones that don't have zone end events will be automatically ended at the time of the last recorded event.
Note:
ZoneRange only supports zone nesting up to ZoneRange.zoneStack nesting levels (currently this is 640, which should be enough for everyone, may be increased in future).
// Filter zones based on the info string. Useful to determine durations of only // certain zones. import tharsis.prof; auto storage = new ubyte[Profiler.maxEventBytes + 2048]; auto profiler = new Profiler(storage); // Simulate 16 'frames' foreach(frame; 0 .. 16) { Zone topLevel = Zone(profiler, "frame"); // Simulate frame overhead. Replace this with your frame code. { Zone nested1 = Zone(profiler, "frameStart"); foreach(i; 0 .. 1000) { continue; } } { Zone nested2 = Zone(profiler, "frameCore"); foreach(i; 0 .. 10000) { continue; } } } import std.algorithm; // Write duration of each instance of the "frameCore" zone. foreach(zone; profiler.profileData.zoneRange.filter!(z => z.info == "frameCore")) { import std.stdio; writeln(zone.duration); }
1 // Sort top-level zones by duration. If there is one top-level zone per frame, this 2 // sorts frames by duration: useful to get the worst-case frames. 3 4 // This example also uses C malloc/free and std.typecons.scoped 5 // to show how to do this without using the GC. 6 7 import tharsis.prof; 8 9 const storageLength = Profiler.maxEventBytes + 1024 * 1024 * 2; 10 11 import core.stdc.stdlib; 12 // A simple typed-slice malloc wrapper function would avoid the ugly cast/slicing. 13 ubyte[] storage = (cast(ubyte*)malloc(storageLength))[0 .. storageLength]; 14 scope(exit) { free(storage.ptr); } 15 16 import std.typecons; 17 auto profiler = scoped!Profiler(storage); 18 19 // std.typecons.scoped! stores the Profiler on the stack. 20 // Simulate 16 'frames' 21 foreach(frame; 0 .. 16) 22 { 23 Zone topLevel = Zone(profiler, "frame"); 24 25 // Simulate frame overhead. Replace this with your frame code. 26 { 27 Zone nested1 = Zone(profiler, "frameStart"); 28 foreach(i; 0 .. 1000) { continue; } 29 } 30 { 31 Zone nested2 = Zone(profiler, "frameCore"); 32 foreach(i; 0 .. 10000) { continue; } 33 } 34 } 35 36 import std.algorithm; 37 auto zones = profiler.profileData.zoneRange; 38 39 // nestLevel of 1 is toplevel. 40 auto topLevel = zones.filter!(z => z.nestLevel == 1); 41 42 const size_t topLevelLength = zones.walkLength; 43 //TODO replace with std.allocator, or better, new containers once added to Phobos 44 ZoneData[] topLevelArray = (cast(ZoneData*)malloc(topLevelLength * ZoneData.sizeof))[0 .. topLevelLength]; 45 scope(exit) { free(topLevelArray.ptr); } 46 47 topLevel.copy(topLevelArray); 48 topLevelArray.sort!((a, b) => a.duration > b.duration); 49 import std.stdio; 50 // Print the 4 longest frames. 51 foreach(frame; topLevelArray[0 .. 4]) 52 { 53 writeln(frame); 54 } 55 56 auto worst = topLevelArray[0]; 57 58 /* Code based on std.container.array.Array: broken due to DMD 2.068 changes. 59 * Getting obsolete anyway, as containers are finally being redesigned by Andrei Alexandrescu. 60 import std.container; 61 // std.container.Array constructor builds an RAII array containing zones from topLevel. 62 // We need an array as we need random access to sort the zones (ZoneRange generates 63 // ZoneData on-the-fly as it processes profiling data, so it has no random access). 64 auto topLevelArray = Array!ZoneData(topLevel); 65 topLevelArray[].sort!((a, b) => a.duration > b.duration); 66 67 import std.stdio; 68 // Print the 4 longest frames. 69 foreach(frame; topLevelArray[0 .. 4]) 70 { 71 writeln(frame); 72 } 73 74 auto worst = topLevelArray[0]; 75 */ 76 77 // Print details about all zones in the worst frame. 78 writeln("Zones in the worst frame:"); 79 foreach(zone; zones.filter!(z => z.startTime >= worst.startTime && z.endTime <= worst.endTime)) 80 { 81 writefln("%s: %s hnsecs from %s to %s", 82 zone.info, zone.duration, zone.startTime, zone.endTime); 83 }
Light-weight range that iterates over zones in profile data.
Constructed from a ForwardRange of Event (e.g. EventRange or a std.algorithm wrapper around an EventRange). Can also be constructed from raw profile data using eventRange().