@@ -93,8 +93,9 @@ typedef struct SpallEndEvent {
9393
9494typedef struct SpallProfile {
9595 double timestamp_unit ;
96- bool (* write )(struct SpallProfile * self , void * data , size_t length );
96+ bool (* write )(struct SpallProfile * self , const void * data , size_t length );
9797 bool (* flush )(struct SpallProfile * self );
98+ void (* close )(struct SpallProfile * self );
9899 union {
99100 FILE * file ;
100101 void * userdata ;
@@ -159,16 +160,18 @@ extern "C" {
159160#endif
160161
161162#ifdef SPALL_BUFFER_PROFILING
163+ static void Spall__BufferProfile (SpallProfile * ctx , SpallBuffer * wb , double spall_time_begin , double spall_time_end , const char * name , int name_len ) {
164+ // precon: ctx
165+ // precon: ctx->write
166+ char temp_buffer_data [2048 ];
167+ SpallBuffer temp_buffer = { temp_buffer_data , sizeof (temp_buffer_data ) };
168+ if (!SpallTraceBeginLenTidPid (ctx , & temp_buffer , name , sizeof (name ) - 1 , (uint32_t )(uintptr_t )wb -> data , 4222222222 , spall_time_begin )) return ;
169+ if (!SpallTraceEndTidPid (ctx , & temp_buffer , (uint32_t )(uintptr_t )wb -> data , 4222222222 , spall_time_end )) return ;
170+ ctx -> write (ctx , temp_buffer_data , temp_buffer .head );
171+ }
162172#define SPALL_BUFFER_PROFILE_BEGIN () double spall_time_begin = (SPALL_BUFFER_PROFILING_GET_TIME())
163173// Don't call this with anything other than a string literal
164- #define SPALL_BUFFER_PROFILE_END (name ) do { \
165- double spall_time_end = (SPALL_BUFFER_PROFILING_GET_TIME()); \
166- char temp_buffer_data[sizeof(SpallBeginEvent) + sizeof("" name "") - 1 + sizeof(SpallEndEvent)]; \
167- SpallBuffer temp_buffer = {temp_buffer_data, sizeof(temp_buffer_data)}; \
168- if (!SpallTraceBeginLenTidPid(ctx, &temp_buffer, name, sizeof(name) - 1, (uint32_t)(uintptr_t)wb->data, 4222222222, spall_time_begin)) return false; \
169- if (!SpallTraceEndTidPid(ctx, &temp_buffer, (uint32_t)(uintptr_t)wb->data, 4222222222, spall_time_end)) return false; \
170- if (!Spall__FileWrite(ctx, temp_buffer_data, sizeof(temp_buffer_data))) return false; \
171- } while (0)
174+ #define SPALL_BUFFER_PROFILE_END (name ) Spall__BufferProfile(ctx, wb, spall_time_begin, (SPALL_BUFFER_PROFILING_GET_TIME()), "" name "", sizeof("" name "") - 1)
172175#else
173176#define SPALL_BUFFER_PROFILE_BEGIN ()
174177#define SPALL_BUFFER_PROFILE_END (name )
@@ -178,7 +181,7 @@ extern char SpallSingleThreadedBufferData[];
178181char SpallSingleThreadedBufferData [1 << 16 ];
179182SpallBuffer SpallSingleThreadedBuffer = {SpallSingleThreadedBufferData , sizeof (SpallSingleThreadedBufferData )};
180183
181- static bool Spall__FileWrite (SpallProfile * ctx , void * p , size_t n ) {
184+ static bool Spall__FileWrite (SpallProfile * ctx , const void * p , size_t n ) {
182185 if (!ctx -> file ) return false;
183186#ifdef SPALL_DEBUG
184187 if (feof (ctx -> file )) return false;
@@ -193,11 +196,28 @@ static bool Spall__FileFlush(SpallProfile *ctx) {
193196 if (fflush (ctx -> file )) return false;
194197 return true;
195198}
199+ static void Spall__FileClose (SpallProfile * ctx ) {
200+ if (!ctx -> file ) return ;
201+
202+ #ifdef SPALL_JSON
203+ #ifdef SPALL_DEBUG
204+ if (!feof (ctx -> file ) && !ferror (ctx -> file ))
205+ #endif
206+ {
207+ fseek (ctx -> file , -2 , SEEK_CUR ); // seek back to overwrite trailing comma
208+ fwrite ("\n]}\n" , sizeof ("\n]}\n" ) - 1 , 1 , ctx -> file );
209+ }
210+ #endif
211+ fflush (ctx -> file );
212+ fclose (ctx -> file );
213+ ctx -> file = NULL ;
214+ }
196215
197216static bool Spall__BufferFlush (SpallProfile * ctx , SpallBuffer * wb ) {
198217 // precon: wb
199218 // precon: wb->data
200219 // precon: wb->head <= wb->length
220+ // precon: !ctx || ctx->write
201221#ifdef SPALL_DEBUG
202222 if (wb -> ctx != ctx ) return false; // Buffer must be bound to this context (or to NULL)
203223#endif
@@ -213,8 +233,11 @@ static bool Spall__BufferFlush(SpallProfile *ctx, SpallBuffer *wb) {
213233
214234static bool Spall__BufferWrite (SpallProfile * ctx , SpallBuffer * wb , void * p , size_t n ) {
215235 // precon: !wb || wb->head < wb->length
216- // precon: ctx->file
236+ // precon: ! ctx || ctx->write
217237 if (!wb ) return ctx -> write (ctx , p , n );
238+ #ifdef SPALL_DEBUG
239+ if (wb -> ctx != ctx ) return false; // Buffer must be bound to this context (or to NULL)
240+ #endif
218241 if (wb -> head + n > wb -> length && !Spall__BufferFlush (ctx , wb )) return false;
219242 if (n > wb -> length ) {
220243 SPALL_BUFFER_PROFILE_BEGIN ();
@@ -263,6 +286,7 @@ static SpallProfile Spall__Init(const char *filename, double timestamp_unit) {
263286 ctx .file = fopen (filename , "wb" ); // TODO: handle utf8 and long paths on windows
264287 ctx .write = Spall__FileWrite ;
265288 ctx .flush = Spall__FileFlush ;
289+ ctx .close = Spall__FileClose ;
266290 if (!ctx .file ) { SpallQuit (& ctx ); return ctx ; }
267291 ctx .timestamp_unit = timestamp_unit ;
268292
@@ -284,17 +308,7 @@ SpallProfile SpallInit (const char *filename, double timestamp_unit) { return
284308
285309void SpallQuit (SpallProfile * ctx ) {
286310 if (!ctx ) return ;
287- if (ctx -> file ) {
288- #ifdef SPALL_JSON
289- fseek (ctx -> file , -2 , SEEK_CUR ); // seek back to overwrite trailing comma
290- fprintf (ctx -> file , "\n]}\n" );
291- fflush (ctx -> file );
292- fclose (ctx -> file );
293- #else
294- fflush (ctx -> file );
295- fclose (ctx -> file );
296- #endif
297- }
311+ if (ctx -> close ) ctx -> close (ctx );
298312
299313 memset (ctx , 0 , sizeof (* ctx ));
300314}
0 commit comments