Advertisement
Pillager86

Profiler

May 14th, 2020
682
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module misanthropyd.debugging.instrumentor;
  2.  
  3. import std.format;
  4. import std.stdio;
  5. import std.string;
  6. import core.thread.osthread;
  7. import core.time;
  8.  
  9. import misanthropyd.core.logger;
  10.  
  11. private struct ProfileResult
  12. {
  13.     string name;
  14.     MonoTime start;
  15.     Duration elapsedTime;
  16.     ThreadID threadID;
  17. }
  18.  
  19. private struct InstrumentationSession
  20. {
  21.     string name;
  22. }
  23.  
  24. /// drop the resulting json file into chrome://tracing/
  25. class Instrumentor
  26. {
  27.     private
  28.     {
  29.         InstrumentationSession* currentSession_ = null;
  30.         File outputFile_;
  31.     }
  32.  
  33.     void beginSession(const string name, const string filepath = "results.json")
  34.     {
  35.         version(profiling)
  36.         {
  37.             synchronized
  38.             {
  39.                 if(currentSession_ != null)
  40.                 {
  41.                     Logger.logf(Logger.Severity.ERROR, "Begin %s when session %s already open.",
  42.                                 name, currentSession_.name);
  43.                 }
  44.                 outputFile_.open(filepath, "w"); // this is supposed to delete the old file each time?
  45.                 if(outputFile_.isOpen)
  46.                 {
  47.                     currentSession_ = new InstrumentationSession(name);
  48.                     writeHeader();
  49.                 }
  50.                 else
  51.                 {
  52.                     Logger.logf(Logger.Severity.ERROR, "Instrumentor could not open file %s", filepath);
  53.                 }
  54.             }
  55.         }
  56.     }
  57.  
  58.     void endSession()
  59.     {
  60.         version(profiling)
  61.         {
  62.             synchronized
  63.             {
  64.                 internalEndSession();
  65.             }
  66.         }
  67.     }
  68.  
  69.     void writeProfile(const ProfileResult result)
  70.     {
  71.         version(profiling)
  72.         {
  73.             import std.conv: to;
  74.             string json;
  75.             string name = result.name.replace('"', '\'');
  76.             json ~= ",{";
  77.             json ~= "\"cat\":\"function\",";
  78.             json ~= "\"dur\":" ~ result.elapsedTime.total!"usecs".to!string ~ ",";
  79.             json ~= "\"name\":\"" ~ name ~ "\",";
  80.             json ~= "\"ph\":\"X\",";
  81.             json ~= "\"pid\":0,";
  82.             json ~= "\"tid\":" ~ result.threadID.to!string ~ ",";
  83.             // immutable TPS = result.start.ticksPerSecond;
  84.             // Logger.logf(Logger.Severity.WARNING, "TicksPerSecond: %s", TPS);
  85.             // TODO: We need to calculate the '1000' here due to platform variance
  86.             json ~= "\"ts\":" ~ (result.start.ticks / 1000).to!string;
  87.             json ~= "}";
  88.  
  89.             synchronized
  90.             {
  91.                 if(currentSession_ != null)
  92.                 {
  93.                     outputFile_.write(json);
  94.                     outputFile_.flush();
  95.                 }
  96.             }
  97.         }
  98.     }
  99.  
  100.     static Instrumentor get()
  101.     {
  102.         if(instance_ is null)
  103.             instance_ = new shared(Instrumentor)();
  104.         return cast(Instrumentor)instance_;
  105.     }
  106.  
  107.     private
  108.     {
  109.         void writeHeader()
  110.         {
  111.             version(profiling)
  112.             {
  113.                 outputFile_.write("{\"otherData\": {},\"traceEvents\":[{}");
  114.                 outputFile_.flush();
  115.             }
  116.         }
  117.  
  118.         void writeFooter()
  119.         {
  120.             version(profiling)
  121.             {
  122.                 outputFile_.write("]}");
  123.                 outputFile_.flush();
  124.             }
  125.         }
  126.  
  127.         void internalEndSession()
  128.         {
  129.             version(profiling)
  130.             {
  131.                 if(currentSession_ != null)
  132.                 {
  133.                     writeFooter();
  134.                     outputFile_.close();
  135.                     destroy(currentSession_);
  136.                     currentSession_ = null;
  137.                 }
  138.             }
  139.         }
  140.  
  141.         static shared Instrumentor instance_;
  142.     }
  143. }
  144.  
  145. /// scope lifetime variable to be declared at top of function to profile
  146. struct InstrumentationTimer
  147. {
  148.     this(const string name)
  149.     {
  150.         name_ = name;
  151.         stopped_ = false;
  152.         startTimepoint_ = MonoTime.currTime();
  153.     }
  154.  
  155.     ~this()
  156.     {
  157.         if(!stopped_) stop();
  158.     }
  159.  
  160.     void stop()
  161.     {
  162.         import std.process: thisThreadID;
  163.         immutable endTimepoint = MonoTime.currTime();
  164.         Duration elapsedTime = endTimepoint - startTimepoint_;
  165.         ProfileResult result = ProfileResult(name_, startTimepoint_, elapsedTime, thisThreadID);
  166.         Instrumentor.get.writeProfile(result);
  167.         stopped_ = true;
  168.     }
  169.  
  170.     private
  171.     {
  172.         string name_;
  173.         MonoTime startTimepoint_;
  174.         bool stopped_;
  175.     }
  176. }
  177.  
  178. version(profiling)
  179. {
  180.     template MdProfileScope(const string name, int line=__LINE__)
  181.     {
  182.         import std.conv: to;
  183.         const char[] MdProfileScope = "auto timer" ~ line.to!string ~ " = InstrumentationTimer(\"" ~ name ~ "\");"; // @suppress(dscanner.style.phobos_naming_convention)
  184.     }
  185. }
  186. else
  187. {
  188.     template MdProfileScope(const string name, int line=__LINE__)
  189.     {
  190.         const char[] MdProfileScope = ""; // @suppress(dscanner.style.phobos_naming_convention)
  191.     }
  192. }
Advertisement
RAW Paste Data Copied
Advertisement