4coder/4ed_profile.cpp

218 lines
4.8 KiB
C++

/*
* 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 <stdio.h>
#include <stdlib.h>
global f32 frame_target = 58000000.f;
internal void
usage(){
fprintf(stderr, "No! Like this, you moron:\n"
"\t<PROFILE-EXE> <PROFILE-DATA> [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