/* * Mr. 4th Dimention - Allen Webster * * 29.03.2017 * * Really basic profiling primitives. (not meant to stay for long) * */ // TOP #define FRED_INTERNAL 1 #include "4tech_defines.h" #include "4ed_profile.h" #include #include global f32 frame_target = 58000000.f; internal void usage(){ fprintf(stderr, "No! Like this, you moron:\n" "\t [min-time-filter]\n"); } internal u32 parse_frame_count(u8 *ptr, u8 *end){ u32 count = 0; for (;ptr < end;){ u8 *frame_base = *(u8**)ptr; ptr += 8; u8 *frame_end = *(u8**)ptr; ptr += 8; umem skip_size = frame_end - frame_base; ptr += skip_size; ++count; } if (ptr != end){ count = 0; } return(count); } struct Parse_Frame_Result{ u8 *next_read_ptr; u8 *output_chunk; b32 still_looping; b32 bad_parse; f32 frame_time; }; internal Parse_Frame_Result parse_frame(u8 *ptr, u8 *end_ptr){ Parse_Frame_Result result = {0}; u8 *frame_base = *(u8**)ptr; ptr += 8; u8 *frame_end = *(u8**)ptr; ptr += 8; umem frame_size = frame_end - frame_base; u8 *frame_start_ptr = ptr; u8 *frame_end_ptr = ptr + frame_size; u8 *out_chunk = (u8*)malloc(frame_size*2); u8 *out_ptr = out_chunk; Profile_Group *group = (Profile_Group*)frame_start_ptr; Profile_Group *group_end = (Profile_Group*)frame_end_ptr; Profile_Group *stack[64]; u32 top = 0; stack[top++] = group; result.frame_time = group->cycle_count / frame_target; for (;group < group_end;){ for (u32 i = 1; i < top; ++i){ *out_ptr++ = ' '; } char *name = group->name; for (u32 i = 0; name[i]; ++i){ *out_ptr++ = name[i]; } *out_ptr++ = ':'; *out_ptr++ = ' '; char str[64]; sprintf(str, "%f", group->cycle_count / frame_target); for (u32 i = 0; str[i]; ++i){ *out_ptr++ = str[i]; } *out_ptr++ = '\n'; ++group; for(;top > 0;){ Profile_Group *group_top = stack[top-1]; umem end_offset = (u8*)group_top->end - frame_base; u8 *this_group_end_ptr = frame_start_ptr + end_offset; Profile_Group *this_group_end = (Profile_Group*)this_group_end_ptr; if (group == this_group_end){ --top; } else{ break; } } stack[top++] = group; } if (top != 1){ result.bad_parse = true; } else{ *out_ptr++ = 0; result.next_read_ptr = frame_end_ptr; result.output_chunk = out_chunk; if (frame_end_ptr != end_ptr){ result.still_looping = true; } } return(result); } internal void print_profile(char *filename, f32 min_filter){ FILE *file = fopen(filename, "rb"); if (!file){ fprintf(stderr, "There ain't no file sittin' around called %s.\n", filename); exit(1); } fseek(file, 0, SEEK_END); u32 size = ftell(file); fseek(file, 0, SEEK_SET); u8 *buffer = (u8*)malloc(size); fread(buffer, 1, size, file); fclose(file); u8 *read_ptr = buffer; u8 *end_ptr = buffer + size; // Frame Count Parse u32 frame_count = parse_frame_count(read_ptr, end_ptr); if (frame_count == 0){ fprintf(stderr, "There's some fricken problem. I didn't get a good frame count!\n"); exit(1); } // Full Parse u8 **output_chunks = (u8**)malloc(frame_count*sizeof(u8*)); u32 chunk_i = 0; Parse_Frame_Result result = {0}; do{ if (chunk_i >= frame_count){ fprintf(stderr, "The parse ain't lined up! You're fired!\n"); exit(1); } result = parse_frame(read_ptr, end_ptr); if (result.bad_parse){ fprintf(stderr, "You've pickled the data nimwit!\n"); exit(1); } read_ptr = result.next_read_ptr; if (result.frame_time >= min_filter){ output_chunks[chunk_i++] = result.output_chunk; } }while(result.still_looping); // Print fprintf(stdout, "Frames: %u (%u)\n", chunk_i, frame_count); for (u32 i = 0; i < chunk_i; ++i){ fprintf(stdout, "%s", output_chunks[i]); } } int main(int argc, char **argv){ if (argc < 2){ usage(); } else{ f32 min_filter = 0.f; if (argc == 3){ min_filter = (f32)atof(argv[2]); } print_profile(argv[1], min_filter); } return(0); } // BOTTOM