Last active
December 16, 2015 00:29
-
-
Save bitbckt/5348042 to your computer and use it in GitHub Desktop.
An example hprof reader.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <arpa/inet.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define HPROF_OK 0 | |
#define HPROF_ERR -1 | |
/* Shamelessly copied from src/share/vm/services/heapDumper.cpp */ | |
enum tag { | |
HPROF_UTF8 = 0x01, | |
HPROF_LOAD_CLASS = 0x02, | |
HPROF_UNLOAD_CLASS = 0x03, | |
HPROF_FRAME = 0x04, | |
HPROF_TRACE = 0x05, | |
HPROF_ALLOC_SITES = 0x06, | |
HPROF_HEAP_SUMMARY = 0x07, | |
HPROF_START_THREAD = 0x0A, | |
HPROF_END_THREAD = 0x0B, | |
HPROF_HEAP_DUMP = 0x0C, | |
HPROF_CPU_SAMPLES = 0x0D, | |
HPROF_CONTROL_SETTINGS = 0x0E, | |
/* 1.0.2 record types */ | |
HPROF_HEAP_DUMP_SEGMENT = 0x1C, | |
HPROF_HEAP_DUMP_END = 0x2C, | |
/* field types */ | |
HPROF_ARRAY_OBJECT = 0x01, | |
HPROF_NORMAL_OBJECT = 0x02, | |
HPROF_BOOLEAN = 0x04, | |
HPROF_CHAR = 0x05, | |
HPROF_FLOAT = 0x06, | |
HPROF_DOUBLE = 0x07, | |
HPROF_BYTE = 0x08, | |
HPROF_SHORT = 0x09, | |
HPROF_INT = 0x0A, | |
HPROF_LONG = 0x0B, | |
/* data-dump sub-records */ | |
HPROF_GC_ROOT_UNKNOWN = 0xFF, | |
HPROF_GC_ROOT_JNI_GLOBAL = 0x01, | |
HPROF_GC_ROOT_JNI_LOCAL = 0x02, | |
HPROF_GC_ROOT_JAVA_FRAME = 0x03, | |
HPROF_GC_ROOT_NATIVE_STACK = 0x04, | |
HPROF_GC_ROOT_STICKY_CLASS = 0x05, | |
HPROF_GC_ROOT_THREAD_BLOCK = 0x06, | |
HPROF_GC_ROOT_MONITOR_USED = 0x07, | |
HPROF_GC_ROOT_THREAD_OBJ = 0x08, | |
HPROF_GC_CLASS_DUMP = 0x20, | |
HPROF_GC_INSTANCE_DUMP = 0x21, | |
HPROF_GC_OBJ_ARRAY_DUMP = 0x22, | |
HPROF_GC_PRIM_ARRAY_DUMP = 0x23 | |
}; | |
static const char *__version = "JAVA PROFILE 1.0.2"; | |
static uint32_t __id_size = 0; | |
static uint64_t __timestamp = 0; | |
static uint32_t | |
btol(unsigned char *b) | |
{ | |
uint32_t l; | |
memcpy(&l, b, sizeof(l)); | |
return ntohl(l); | |
} | |
static uint64_t | |
btoll(unsigned char *b) | |
{ | |
uint64_t l = 0; | |
uint32_t msb, lsb; | |
memcpy(&msb, b, sizeof(msb)); | |
l |= ntohl(msb); | |
l <<= 32; | |
memcpy(&lsb, b + 4, sizeof(lsb)); | |
l |= ntohl(lsb); | |
return l; | |
} | |
static uint8_t | |
readu1(FILE *file) | |
{ | |
unsigned char buf; | |
fread(&buf, sizeof(buf), 1, file); | |
return (uint8_t)buf; | |
} | |
static uint32_t | |
readu4(FILE *file) | |
{ | |
unsigned char buf[4]; | |
fread(buf, sizeof(*buf), 4, file); | |
return btol(buf); | |
} | |
static uint64_t | |
readu8(FILE *file) | |
{ | |
unsigned char buf[8]; | |
fread(buf, sizeof(*buf), 8, file); | |
return btoll(buf); | |
} | |
static int | |
version_check(FILE *file) | |
{ | |
int ret; | |
char buf[21]; | |
size_t bytes; | |
size_t len = strlen(__version) + 1; /* + NUL */ | |
bytes = fread(buf, 1, len, file); | |
ret = ferror(file); | |
if (ret != 0) { | |
return ret; | |
} | |
if (bytes == len) { | |
return strncmp(__version, buf, len - 1); | |
} else { | |
return HPROF_ERR; | |
} | |
} | |
static int | |
id_size_check(FILE *file) | |
{ | |
__id_size = readu4(file); | |
return HPROF_OK; | |
} | |
static int | |
timestamp_check(FILE *file) | |
{ | |
__timestamp = readu8(file); | |
return HPROF_OK; | |
} | |
static int | |
record_check(FILE *file) | |
{ | |
enum tag tag; | |
uint32_t bytes; | |
tag = readu1(file); | |
(void)readu4(file); /* usecs. since __timestamp */ | |
bytes = readu4(file); | |
switch (tag) { | |
case HPROF_HEAP_SUMMARY: | |
printf("found heap summary!\n"); | |
break; | |
default: | |
break; | |
} | |
fseek(file, bytes, SEEK_CUR); | |
return HPROF_OK; | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
FILE *file = NULL; | |
int ret = EXIT_SUCCESS; | |
if (argc < 2) { | |
fprintf(stderr, "Usage: hprof <file>\n"); | |
ret = EXIT_FAILURE; | |
goto out; | |
} | |
file = fopen(argv[1], "r"); | |
if (file == NULL) { | |
perror("fopen(): "); | |
ret = EXIT_FAILURE; | |
goto out; | |
} | |
ret = version_check(file); | |
if (ret != 0) { | |
fprintf(stderr, "version_check(): %d\n", ret); | |
ret = EXIT_FAILURE; | |
goto out; | |
} else { | |
printf("version check passed\n"); | |
} | |
ret = id_size_check(file); | |
if (ret != 0) { | |
fprintf(stderr, "id_size_check(): %d\n", ret); | |
ret = EXIT_FAILURE; | |
goto out; | |
} else { | |
printf("identifier size %d\n", __id_size); | |
} | |
ret = timestamp_check(file); | |
if (ret != 0) { | |
fprintf(stderr, "timestamp_check(): %d\n", ret); | |
ret = EXIT_FAILURE; | |
goto out; | |
} else { | |
printf("timestamp %ld\n", __timestamp); | |
} | |
while (!feof(file)) { | |
ret = record_check(file); | |
if (ret != 0) { | |
fprintf(stderr, "record_check(): %d\n", ret); | |
ret = EXIT_FAILURE; | |
goto out; | |
} | |
} | |
out: | |
if (file) { | |
fclose(file); | |
} | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment