Fix and test for memory leaks

git-svn-id: file://localhost/svn/verilator/trunk/verilator@768 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
Wilson Snyder 2006-08-30 19:50:24 +00:00
parent c82235a2de
commit b7485bfc0b
7 changed files with 174 additions and 20 deletions

View File

@ -9,7 +9,9 @@ indicates the contributor was also the author of the fix; Thanks!
*** Added `systemc_dtor for destructor extentions. [Allan Cochrane]
**** Declare tables static, to reduce D-Cache miss rate.
**** Declare optimized lookup tables as 'static', to reduce D-Cache miss rate.
**** Fix memory leak when destroying modules. [John Stroebel]
**** Fix $display %m name not matching Verilog name inside SystemC modules.

View File

@ -23,6 +23,7 @@
//=========================================================================
#include "verilated.h"
#include <string.h>
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
@ -244,17 +245,28 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
const char* Verilated::catName(const char* n1, const char* n2) {
// Returns new'ed data
// Used by symbol table creation to make module names
char* str = new char[strlen(n1)+strlen(n2)+2];
strcpy(str,n1);
strcat(str,n2);
return str;
static char* strp = NULL;
static int len = -1;
int newlen = strlen(n1)+strlen(n2)+2;
if (newlen > len) {
if (strp) delete [] strp;
strp = new char[newlen];
len = newlen;
}
strcpy(strp,n1);
strcat(strp,n2);
return strp;
}
//===========================================================================
// VerilatedModule:: Methods
VerilatedModule::VerilatedModule(const char* name)
: m_name(name) {
VerilatedModule::VerilatedModule(const char* namep)
: m_namep(strdup(namep)) {
}
VerilatedModule::~VerilatedModule() {
if (m_namep) free((void*)m_namep); m_namep=NULL;
}
//===========================================================================

View File

@ -57,12 +57,13 @@ class SpTraceVcdCFile;
class VerilatedModule {
private:
const char* m_name; ///< Module name
VerilatedModule() {} ///< N/A, always use named constructor below
const char* m_namep; ///< Module name
VerilatedModule(); ///< N/A, always use named constructor below
VerilatedModule(const VerilatedModule& ); ///< N/A, no copying modules
public:
VerilatedModule(const char* name); ///< Create module with given hierarchy name
~VerilatedModule() {}
const char* name() const { return m_name; } ///< Return name of module
VerilatedModule(const char* namep); ///< Create module with given hierarchy name
~VerilatedModule();
const char* name() const { return m_namep; } ///< Return name of module
};
//=========================================================================

View File

@ -359,6 +359,7 @@ sub compile {
"VM_PREFIX=$self->{VM_PREFIX}",
($param{make_main}?"":"MAKE_MAIN=0"),
"$self->{VM_PREFIX}", # not default, as we don't need archive
($param{make_flags}||""),
]);
}
}
@ -518,7 +519,7 @@ sub _make_main {
print $fh "#include \"SpTraceVcdC.cpp\"\n" if $self->{trace};
print $fh "#include \"SpCoverage.cpp\"\n" if $self->{coverage};
print $fh "$VM_PREFIX *top;\n";
print $fh "$VM_PREFIX * topp;\n";
if (!$self->sp) {
print $fh "unsigned int main_time = false;\n";
print $fh "double sc_time_stamp () {\n";
@ -536,15 +537,15 @@ sub _make_main {
print $fh " double sim_time = 1000;\n";
}
print $fh " Verilated::debug(".($Opt_Verilated_Debug?1:0).");\n";
print $fh " top = new $VM_PREFIX (\"TOP\");\n";
print $fh " topp = new $VM_PREFIX (\"TOP\");\n";
my $set;
if ($self->sp) {
print $fh " SP_PIN(top,fastclk,fastclk);\n" if $self->{inputs}{fastclk};
print $fh " SP_PIN(top,clk,clk);\n" if $self->{inputs}{clk};
print $fh " SP_PIN(topp,fastclk,fastclk);\n" if $self->{inputs}{fastclk};
print $fh " SP_PIN(topp,clk,clk);\n" if $self->{inputs}{clk};
$set = "";
} else {
print $fh " top->eval();\n";
$set = "top->";
print $fh " topp->eval();\n";
$set = "topp->";
}
print $fh " ${set}fastclk = true;\n" if $self->{inputs}{fastclk};
print $fh " ${set}clk = true;\n" if $self->{inputs}{clk};
@ -570,9 +571,9 @@ sub _make_main {
print $fh " if (!Verilated::gotFinish()) {\n";
print $fh ' vl_fatal(__FILE__,__LINE__,"main", "%Error: Timeout; never got a $finish");',"\n";
print $fh " }\n";
print $fh " top->final();\n";
print $fh " topp->final();\n";
print $fh " SpCoverage::write(\"",$self->{coverage_filename},"\");\n" if $self->{coverage};
print $fh " delete top;\n";
print $fh " delete topp; topp=NULL;\n";
print $fh " exit(0L);\n";
print $fh "}\n";
$fh->close();

93
test_regress/t/t_leak.cpp Normal file
View File

@ -0,0 +1,93 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test driver/expect definition
//
// Copyright 2003-2006 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// General Public License or the Perl Artistic License.
#include <stdlib.h>
#include <stdio.h>
#include <verilated.h>
#include "Vt_leak.h"
unsigned int main_time = false;
double sc_time_stamp () {
return main_time;
}
void vl_finish (const char* filename, int linenum, const char* hier) {
// Define it to not print a message
if (0 && filename && linenum && hier) {}
Verilated::gotFinish(true);
}
long long get_memory_usage() {
// Return memory usage. Return 0 if the system doesn't look quite right.
#if 0 // BSD only.
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
return usage.ru_ixrss + usage.ru_idrss + usage.ru_isrss;
#endif
FILE* fp = fopen("/proc/self/stat", "r");
if (!fp) return 0;
int ps_ign;
long long ps_vsize, ps_rss;
int items = fscanf(fp, ("%d (%*[^) ]) %*1s %d %*d %*d %*d %*d %u"
" %u %u %u %u %d %d %d %d"
" %*d %*d %*u %*u %d %llu %llu "),
&ps_ign, &ps_ign, &ps_ign,
&ps_ign, &ps_ign, &ps_ign, &ps_ign,
&ps_ign, &ps_ign, &ps_ign, &ps_ign,
&ps_ign, &ps_vsize, &ps_rss);
fclose(fp);
if (items >= 14) {
return ps_vsize;
} else {
return 0;
}
}
void make_and_destroy () {
Vt_leak* topp = new Vt_leak;
Verilated::debug(0);
Verilated::gotFinish(0);
topp->eval();
topp->clk = true;
while (!Verilated::gotFinish()) {
main_time+=5;
topp->clk=!topp->clk;
topp->eval();
}
delete topp; topp=NULL;
}
int main (int argc, char *argv[]) {
long long firstUsage = get_memory_usage();
// Warmup phase
for (int i=0; i<1000; i++) {
make_and_destroy();
}
firstUsage = get_memory_usage();
printf("Memory size %lld bytes\n", firstUsage);
int loops = 100*1000;
for (int left=loops; left>0;) {
for (int j=0; j<1000; j++, left--) {
make_and_destroy();
}
}
long long leaked = get_memory_usage() - firstUsage;
if (leaked > 64*1024) { // Have to allow some slop for this code.
printf ("Leaked %lld bytes, or ~ %lld bytes/construt\n", leaked, leaked/loops);
vl_fatal(__FILE__,__LINE__,"top", "Leaked memory\n");
}
printf ("*-* All Finished *-*\n");
}

21
test_regress/t/t_leak.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
compile (
make_top_shell => 0,
make_main => 0,
make_flags => "OPT_FAST=-DVL_USER_FINISH",
v_flags2 => ["--exe t/$Last_Self->{name}.cpp"],
) if $Last_Self->{v3};
execute (
check_finished=>1,
) if $Last_Self->{v3};
ok(1);
1;

24
test_regress/t/t_leak.v Normal file
View File

@ -0,0 +1,24 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (clk);
sub sub ();
input clk;
integer cyc=1;
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==2) begin
$finish;
end
end
endmodule
module sub;
/* verilator public_module */
endmodule