Optimize the per-signal vcd_info structure
In a typical debug simulation run, a user tracing all the signals in the simulation may wind up creating millions of these. Rework the vcd_info structure to be more compact and possibly faster to scan.
This commit is contained in:
parent
94d75e0170
commit
76cc024f67
125
vpi/sys_lxt2.c
125
vpi/sys_lxt2.c
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -45,19 +45,73 @@ static struct lxt2_wr_trace *dump_file = NULL;
|
||||||
|
|
||||||
static void* lxt2_thread(void*arg);
|
static void* lxt2_thread(void*arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage a table of all the dump-enabled vcd item. The cells of this
|
||||||
|
* table are allocated incrementally, but are released all at once, so
|
||||||
|
* we can allocate the items in chunks.
|
||||||
|
*/
|
||||||
struct vcd_info {
|
struct vcd_info {
|
||||||
vpiHandle item;
|
vpiHandle item;
|
||||||
vpiHandle cb;
|
vpiHandle cb;
|
||||||
struct t_vpi_time time;
|
|
||||||
struct lxt2_wr_symbol *sym;
|
struct lxt2_wr_symbol *sym;
|
||||||
struct vcd_info *next;
|
|
||||||
struct vcd_info *dmp_next;
|
struct vcd_info *dmp_next;
|
||||||
int scheduled;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vcd_info_chunk {
|
||||||
|
struct vcd_info_chunk*chunk_next;
|
||||||
|
uint16_t chunk_fill;
|
||||||
|
struct vcd_info data[0x10000];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vcd_info_chunk*info_chunk_list = 0;
|
||||||
|
|
||||||
|
struct vcd_info*new_vcd_info(void)
|
||||||
|
{
|
||||||
|
struct vcd_info_chunk*cur_chunk = info_chunk_list;
|
||||||
|
if (cur_chunk == 0 || cur_chunk->chunk_fill == 0xffff) {
|
||||||
|
struct vcd_info_chunk*tmp = calloc(1, sizeof(struct vcd_info_chunk));
|
||||||
|
tmp->chunk_fill = 0;
|
||||||
|
tmp->chunk_next = cur_chunk;
|
||||||
|
info_chunk_list = cur_chunk = tmp;
|
||||||
|
return info_chunk_list->data + 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vcd_info*ptr = cur_chunk->data + cur_chunk->chunk_fill;
|
||||||
|
cur_chunk->chunk_fill += 1;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void functor_all_vcd_info( void (*fun) (struct vcd_info*info) )
|
||||||
|
{
|
||||||
|
struct vcd_info_chunk*cur;
|
||||||
|
for (cur = info_chunk_list ; cur ; cur = cur->chunk_next) {
|
||||||
|
int idx;
|
||||||
|
struct vcd_info*ptr;
|
||||||
|
for (idx=0, ptr=cur->data ; idx <= cur->chunk_fill ; idx += 1, ptr += 1)
|
||||||
|
fun (ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_all_vcd_info(void)
|
||||||
|
{
|
||||||
|
while (info_chunk_list) {
|
||||||
|
struct vcd_info_chunk*tmp = info_chunk_list->chunk_next;
|
||||||
|
free(info_chunk_list);
|
||||||
|
info_chunk_list = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use this pointer to keep a list of vcd_info items that are
|
||||||
|
* scheduled to be dumped. Use the VCD_INFO_ENDP value as a trailer
|
||||||
|
* pointer instead of 0 so that individual vcd_info objects can tell
|
||||||
|
* if they are in the list already, even if they are at the end of the
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
# define VCD_INFO_ENDP ((struct vcd_info*)1)
|
||||||
|
static struct vcd_info *vcd_dmp_list = VCD_INFO_ENDP;
|
||||||
|
static struct t_vpi_time vcd_dmp_time;
|
||||||
|
|
||||||
static struct vcd_info *vcd_list = NULL;
|
|
||||||
static struct vcd_info *vcd_dmp_list = NULL;
|
|
||||||
static PLI_UINT64 vcd_cur_time = 0;
|
static PLI_UINT64 vcd_cur_time = 0;
|
||||||
static int dump_is_off = 0;
|
static int dump_is_off = 0;
|
||||||
static long dump_limit = 0;
|
static long dump_limit = 0;
|
||||||
|
|
@ -207,23 +261,17 @@ __inline__ static int dump_header_pending(void)
|
||||||
*/
|
*/
|
||||||
static void vcd_checkpoint()
|
static void vcd_checkpoint()
|
||||||
{
|
{
|
||||||
struct vcd_info*cur;
|
functor_all_vcd_info( show_this_item );
|
||||||
|
|
||||||
for (cur = vcd_list ; cur ; cur = cur->next)
|
|
||||||
show_this_item(cur);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vcd_checkpoint_x()
|
static void vcd_checkpoint_x()
|
||||||
{
|
{
|
||||||
struct vcd_info*cur;
|
functor_all_vcd_info( show_this_item_x );
|
||||||
|
|
||||||
for (cur = vcd_list ; cur ; cur = cur->next)
|
|
||||||
show_this_item_x(cur);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PLI_INT32 variable_cb_2(p_cb_data cause)
|
static PLI_INT32 variable_cb_2(p_cb_data cause)
|
||||||
{
|
{
|
||||||
struct vcd_info* info = vcd_dmp_list;
|
assert(cause->time->type == vpiSimTime);
|
||||||
PLI_UINT64 now = timerec_to_time64(cause->time);
|
PLI_UINT64 now = timerec_to_time64(cause->time);
|
||||||
|
|
||||||
if (now != vcd_cur_time) {
|
if (now != vcd_cur_time) {
|
||||||
|
|
@ -231,12 +279,12 @@ static PLI_INT32 variable_cb_2(p_cb_data cause)
|
||||||
vcd_cur_time = now;
|
vcd_cur_time = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
while (vcd_dmp_list != VCD_INFO_ENDP) {
|
||||||
show_this_item(info);
|
struct vcd_info* info = vcd_dmp_list;
|
||||||
info->scheduled = 0;
|
show_this_item(info);
|
||||||
} while ((info = info->dmp_next) != 0);
|
vcd_dmp_list = info->dmp_next;
|
||||||
|
info->dmp_next = 0;
|
||||||
vcd_dmp_list = 0;
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +297,7 @@ static PLI_INT32 variable_cb_1(p_cb_data cause)
|
||||||
if (dump_is_full) return 0;
|
if (dump_is_full) return 0;
|
||||||
if (dump_is_off) return 0;
|
if (dump_is_off) return 0;
|
||||||
if (dump_header_pending()) return 0;
|
if (dump_header_pending()) return 0;
|
||||||
if (info->scheduled) return 0;
|
if (info->dmp_next) return 0;
|
||||||
|
|
||||||
if ((dump_limit > 0) && (ftell(dump_file->handle) > dump_limit)) {
|
if ((dump_limit > 0) && (ftell(dump_file->handle) > dump_limit)) {
|
||||||
dump_is_full = 1;
|
dump_is_full = 1;
|
||||||
|
|
@ -258,14 +306,15 @@ static PLI_INT32 variable_cb_1(p_cb_data cause)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vcd_dmp_list) {
|
if (vcd_dmp_list == VCD_INFO_ENDP) {
|
||||||
|
vcd_dmp_time.type = vpiSuppressTime;
|
||||||
cb = *cause;
|
cb = *cause;
|
||||||
|
cb.time = &vcd_dmp_time;
|
||||||
cb.reason = cbReadOnlySynch;
|
cb.reason = cbReadOnlySynch;
|
||||||
cb.cb_rtn = variable_cb_2;
|
cb.cb_rtn = variable_cb_2;
|
||||||
vpi_register_cb(&cb);
|
vpi_register_cb(&cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
info->scheduled = 1;
|
|
||||||
info->dmp_next = vcd_dmp_list;
|
info->dmp_next = vcd_dmp_list;
|
||||||
vcd_dmp_list = info;
|
vcd_dmp_list = info;
|
||||||
|
|
||||||
|
|
@ -291,8 +340,6 @@ static PLI_INT32 dumpvars_cb(p_cb_data cause)
|
||||||
|
|
||||||
static PLI_INT32 finish_cb(p_cb_data cause)
|
static PLI_INT32 finish_cb(p_cb_data cause)
|
||||||
{
|
{
|
||||||
struct vcd_info *cur, *next;
|
|
||||||
|
|
||||||
if (finish_status != 0) return 0;
|
if (finish_status != 0) return 0;
|
||||||
|
|
||||||
finish_status = 1;
|
finish_status = 1;
|
||||||
|
|
@ -303,11 +350,7 @@ static PLI_INT32 finish_cb(p_cb_data cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
vcd_work_terminate();
|
vcd_work_terminate();
|
||||||
for (cur = vcd_list ; cur ; cur = next) {
|
delete_all_vcd_info();
|
||||||
next = cur->next;
|
|
||||||
free(cur);
|
|
||||||
}
|
|
||||||
vcd_list = 0;
|
|
||||||
|
|
||||||
vcd_scope_names_delete();
|
vcd_scope_names_delete();
|
||||||
nexus_ident_delete();
|
nexus_ident_delete();
|
||||||
|
|
@ -610,27 +653,23 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||||
|
|
||||||
if (nexus_id) set_nexus_ident(nexus_id, ident);
|
if (nexus_id) set_nexus_ident(nexus_id, ident);
|
||||||
|
|
||||||
info = malloc(sizeof(*info));
|
info = new_vcd_info();
|
||||||
|
|
||||||
info->time.type = vpiSimTime;
|
|
||||||
info->item = item;
|
info->item = item;
|
||||||
info->sym = lxt2_wr_symbol_add(dump_file, ident,
|
info->sym = lxt2_wr_symbol_add(dump_file, ident,
|
||||||
0 /* array rows */,
|
0 /* array rows */,
|
||||||
vpi_get(vpiLeftRange, item),
|
vpi_get(vpiLeftRange, item),
|
||||||
vpi_get(vpiRightRange, item),
|
vpi_get(vpiRightRange, item),
|
||||||
LXT2_WR_SYM_F_BITS);
|
LXT2_WR_SYM_F_BITS);
|
||||||
info->scheduled = 0;
|
info->dmp_next = 0;
|
||||||
|
|
||||||
cb.time = &info->time;
|
cb.time = 0;
|
||||||
cb.user_data = (char*)info;
|
cb.user_data = (char*)info;
|
||||||
cb.value = NULL;
|
cb.value = NULL;
|
||||||
cb.obj = item;
|
cb.obj = item;
|
||||||
cb.reason = cbValueChange;
|
cb.reason = cbValueChange;
|
||||||
cb.cb_rtn = variable_cb_1;
|
cb.cb_rtn = variable_cb_1;
|
||||||
|
|
||||||
info->next = vcd_list;
|
|
||||||
vcd_list = info;
|
|
||||||
|
|
||||||
info->cb = vpi_register_cb(&cb);
|
info->cb = vpi_register_cb(&cb);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -651,26 +690,22 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||||
ident = strdup_sh(&name_heap, tmp);
|
ident = strdup_sh(&name_heap, tmp);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
}
|
}
|
||||||
info = malloc(sizeof(*info));
|
info = new_vcd_info();
|
||||||
|
|
||||||
info->time.type = vpiSimTime;
|
|
||||||
info->item = item;
|
info->item = item;
|
||||||
info->sym = lxt2_wr_symbol_add(dump_file, ident,
|
info->sym = lxt2_wr_symbol_add(dump_file, ident,
|
||||||
0 /* array rows */,
|
0 /* array rows */,
|
||||||
vpi_get(vpiSize, item)-1,
|
vpi_get(vpiSize, item)-1,
|
||||||
0, LXT2_WR_SYM_F_DOUBLE);
|
0, LXT2_WR_SYM_F_DOUBLE);
|
||||||
info->scheduled = 0;
|
info->dmp_next = 0;
|
||||||
|
|
||||||
cb.time = &info->time;
|
cb.time = 0;
|
||||||
cb.user_data = (char*)info;
|
cb.user_data = (char*)info;
|
||||||
cb.value = NULL;
|
cb.value = NULL;
|
||||||
cb.obj = item;
|
cb.obj = item;
|
||||||
cb.reason = cbValueChange;
|
cb.reason = cbValueChange;
|
||||||
cb.cb_rtn = variable_cb_1;
|
cb.cb_rtn = variable_cb_1;
|
||||||
|
|
||||||
info->next = vcd_list;
|
|
||||||
vcd_list = info;
|
|
||||||
|
|
||||||
info->cb = vpi_register_cb(&cb);
|
info->cb = vpi_register_cb(&cb);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue