mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 12:17:35 +00:00
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:
parent
c82235a2de
commit
b7485bfc0b
4
Changes
4
Changes
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
|
@ -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
93
test_regress/t/t_leak.cpp
Normal 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
21
test_regress/t/t_leak.pl
Executable 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
24
test_regress/t/t_leak.v
Normal 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
|
Loading…
Reference in New Issue
Block a user