mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Add simple profiling class to accumulate Stmt usage stats across runs.
Use the BROFILER_FILE environment variable to point to a file in which Stmt usage statistics from Bro script-layer can be output. This should be able to be used to check Bro script coverage that that e.g. the entire test suite covers.
This commit is contained in:
parent
c8839da069
commit
8f8290c852
8 changed files with 181 additions and 1 deletions
82
src/Brofiler.cc
Normal file
82
src/Brofiler.cc
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include <cstdio>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include "Brofiler.h"
|
||||
#include "util.h"
|
||||
|
||||
Brofiler::Brofiler()
|
||||
: delim('\t')
|
||||
{
|
||||
}
|
||||
|
||||
Brofiler::~Brofiler()
|
||||
{
|
||||
}
|
||||
|
||||
void Brofiler::ReadStats()
|
||||
{
|
||||
char* bf = getenv("BROFILER_FILE");
|
||||
if ( ! bf ) return;
|
||||
FILE* f = fopen(bf, "r");
|
||||
if ( ! f )
|
||||
{
|
||||
fprintf(stderr, "Failed to open Brofiler file '%s' for reading\n", bf);
|
||||
return;
|
||||
}
|
||||
|
||||
char line[16384];
|
||||
string delimiter;
|
||||
delimiter = delim;
|
||||
while( fgets(line, sizeof(line), f) )
|
||||
{
|
||||
line[strlen(line) - 1] = 0; //remove newline
|
||||
string cnt(strtok(line, delimiter.c_str()));
|
||||
string location(strtok(0, delimiter.c_str()));
|
||||
string desc(strtok(0, delimiter.c_str()));
|
||||
pair<string, string> location_desc(location, desc);
|
||||
uint64 count;
|
||||
atoi_n(cnt.size(), cnt.c_str(), 0, 10, count);
|
||||
usage_map[location_desc] = count;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void Brofiler::WriteStats()
|
||||
{
|
||||
char* bf = getenv("BROFILER_FILE");
|
||||
if ( ! bf ) return;
|
||||
|
||||
FILE* f = fopen(bf, "w");
|
||||
if ( ! f )
|
||||
{
|
||||
fprintf(stderr, "Failed to open Brofiler file '%s' for writing\n", bf);
|
||||
return;
|
||||
}
|
||||
|
||||
for ( list<const Stmt*>::const_iterator it = stmts.begin();
|
||||
it != stmts.end(); ++it )
|
||||
{
|
||||
ODesc location_info;
|
||||
(*it)->GetLocationInfo()->Describe(&location_info);
|
||||
ODesc desc_info;
|
||||
(*it)->Describe(&desc_info);
|
||||
string desc(desc_info.Description());
|
||||
for_each(desc.begin(), desc.end(), canonicalize_desc());
|
||||
pair<string, string> location_desc(location_info.Description(), desc);
|
||||
if ( usage_map.find(location_desc) != usage_map.end() )
|
||||
usage_map[location_desc] += (*it)->GetAccessCount();
|
||||
else
|
||||
usage_map[location_desc] = (*it)->GetAccessCount();
|
||||
}
|
||||
|
||||
map<pair<string, string>, uint64 >::const_iterator it;
|
||||
for ( it = usage_map.begin(); it != usage_map.end(); ++it )
|
||||
{
|
||||
fprintf(f, "%"PRIu64"%c%s%c%s\n", it->second, delim,
|
||||
it->first.first.c_str(), delim, it->first.second.c_str());
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
65
src/Brofiler.h
Normal file
65
src/Brofiler.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef BROFILER_H_
|
||||
#define BROFILER_H_
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <list>
|
||||
#include <Stmt.h>
|
||||
|
||||
|
||||
/**
|
||||
* A simple class for managing stats of Bro script coverage across Bro runs.
|
||||
*/
|
||||
class Brofiler {
|
||||
public:
|
||||
Brofiler();
|
||||
virtual ~Brofiler();
|
||||
|
||||
/**
|
||||
* Imports Bro script Stmt usage information from file pointed to by
|
||||
* environment variable BROFILER_FILE.
|
||||
*/
|
||||
void ReadStats();
|
||||
|
||||
/**
|
||||
* Combines usage stats from current run with any read from ReadStats(),
|
||||
* then writes information to file pointed to by environment variable
|
||||
* BROFILER_FILE.
|
||||
*/
|
||||
void WriteStats();
|
||||
|
||||
void SetDelim(char d) { delim = d; }
|
||||
|
||||
/**
|
||||
* The current, global Brofiler instance creates this list at parse-time.
|
||||
*/
|
||||
list<const Stmt*> stmts;
|
||||
|
||||
private:
|
||||
/**
|
||||
*
|
||||
* This maps Stmt location-desc pairs to the total number of times that
|
||||
* Stmt has been executed. The map can be initialized from a file at
|
||||
* startup time and modified at shutdown time before writing back
|
||||
* to a file.
|
||||
*/
|
||||
map<pair<string, string>, uint64> usage_map;
|
||||
|
||||
/**
|
||||
* The character to use to delimit Brofiler output files. Default is '\t'.
|
||||
*/
|
||||
char delim;
|
||||
|
||||
/**
|
||||
* A canonicalization routine for Stmt descriptions containing characters
|
||||
* that don't agree with the output format of Brofiler.
|
||||
*/
|
||||
struct canonicalize_desc {
|
||||
void operator() (char& c)
|
||||
{
|
||||
if ( c == '\n' ) c = ' ';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* BROFILER_H_ */
|
|
@ -281,6 +281,7 @@ set(bro_SRCS
|
|||
BPF_Program.cc
|
||||
BroDoc.cc
|
||||
BroDocObj.cc
|
||||
Brofiler.cc
|
||||
BroString.cc
|
||||
CCL.cc
|
||||
ChunkedIO.cc
|
||||
|
|
|
@ -258,6 +258,7 @@ static BroFile* print_stdout = 0;
|
|||
|
||||
Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
|
||||
{
|
||||
RegisterAccess();
|
||||
if ( ! print_stdout )
|
||||
print_stdout = new BroFile(stdout);
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
|
||||
void RegisterAccess() const { last_access = network_time; access_count++; }
|
||||
void AccessStats(ODesc* d) const;
|
||||
uint32 GetAccessCount() const { return access_count; }
|
||||
|
||||
virtual void Describe(ODesc* d) const;
|
||||
|
||||
|
|
|
@ -47,9 +47,12 @@ extern "C" void OPENSSL_add_all_algorithms_conf(void);
|
|||
#include "ConnCompressor.h"
|
||||
#include "DPM.h"
|
||||
#include "BroDoc.h"
|
||||
#include "Brofiler.h"
|
||||
|
||||
#include "binpac_bro.h"
|
||||
|
||||
Brofiler brofiler;
|
||||
|
||||
#ifndef HAVE_STRSEP
|
||||
extern "C" {
|
||||
char* strsep(char**, const char*);
|
||||
|
@ -260,6 +263,8 @@ void terminate_bro()
|
|||
|
||||
terminating = true;
|
||||
|
||||
brofiler.WriteStats();
|
||||
|
||||
EventHandlerPtr bro_done = internal_handler("bro_done");
|
||||
if ( bro_done )
|
||||
mgr.QueueEvent(bro_done, new val_list);
|
||||
|
@ -335,6 +340,7 @@ static void bro_new_handler()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
brofiler.ReadStats();
|
||||
bro_argc = argc;
|
||||
bro_argv = new char* [argc];
|
||||
|
||||
|
|
25
src/parse.y
25
src/parse.y
|
@ -80,10 +80,12 @@
|
|||
#include "Reporter.h"
|
||||
#include "BroDoc.h"
|
||||
#include "BroDocObj.h"
|
||||
#include "Brofiler.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
extern Brofiler brofiler;
|
||||
extern BroDoc* current_reST_doc;
|
||||
extern int generate_documentation;
|
||||
extern std::list<std::string>* reST_doc_comments;
|
||||
|
@ -1330,93 +1332,111 @@ stmt:
|
|||
{
|
||||
set_location(@1, @3);
|
||||
$$ = new PrintStmt($2);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_EVENT event ';'
|
||||
{
|
||||
set_location(@1, @3);
|
||||
$$ = new EventStmt($2);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_IF '(' expr ')' stmt
|
||||
{
|
||||
set_location(@1, @4);
|
||||
$$ = new IfStmt($3, $5, new NullStmt());
|
||||
//brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_IF '(' expr ')' stmt TOK_ELSE stmt
|
||||
{
|
||||
set_location(@1, @4);
|
||||
$$ = new IfStmt($3, $5, $7);
|
||||
//brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_SWITCH expr '{' case_list '}'
|
||||
{
|
||||
set_location(@1, @2);
|
||||
$$ = new SwitchStmt($2, $4);
|
||||
//brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| for_head stmt
|
||||
{ $1->AsForStmt()->AddBody($2); }
|
||||
{
|
||||
$1->AsForStmt()->AddBody($2);
|
||||
//brofiler.stmts.push_back($1);
|
||||
}
|
||||
|
||||
| TOK_NEXT ';'
|
||||
{
|
||||
set_location(@1, @2);
|
||||
$$ = new NextStmt;
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_BREAK ';'
|
||||
{
|
||||
set_location(@1, @2);
|
||||
$$ = new BreakStmt;
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_RETURN ';'
|
||||
{
|
||||
set_location(@1, @2);
|
||||
$$ = new ReturnStmt(0);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_RETURN expr ';'
|
||||
{
|
||||
set_location(@1, @2);
|
||||
$$ = new ReturnStmt($2);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_ADD expr ';'
|
||||
{
|
||||
set_location(@1, @3);
|
||||
$$ = new AddStmt($2);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_DELETE expr ';'
|
||||
{
|
||||
set_location(@1, @3);
|
||||
$$ = new DelStmt($2);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_LOCAL local_id opt_type init_class opt_init opt_attr ';'
|
||||
{
|
||||
set_location(@1, @7);
|
||||
$$ = add_local($2, $3, $4, $5, $6, VAR_REGULAR);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_CONST local_id opt_type init_class opt_init opt_attr ';'
|
||||
{
|
||||
set_location(@1, @6);
|
||||
$$ = add_local($2, $3, $4, $5, $6, VAR_CONST);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_WHEN '(' expr ')' stmt
|
||||
{
|
||||
set_location(@3, @5);
|
||||
$$ = new WhenStmt($3, $5, 0, 0, false);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_WHEN '(' expr ')' stmt TOK_TIMEOUT expr '{' stmt_list '}'
|
||||
{
|
||||
set_location(@3, @8);
|
||||
$$ = new WhenStmt($3, $5, $9, $7, false);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1424,18 +1444,21 @@ stmt:
|
|||
{
|
||||
set_location(@4, @6);
|
||||
$$ = new WhenStmt($4, $6, 0, 0, true);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| TOK_RETURN TOK_WHEN '(' expr ')' stmt TOK_TIMEOUT expr '{' stmt_list '}'
|
||||
{
|
||||
set_location(@4, @9);
|
||||
$$ = new WhenStmt($4, $6, $10, $8, true);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| expr ';'
|
||||
{
|
||||
set_location(@1, @2);
|
||||
$$ = new ExprStmt($1);
|
||||
brofiler.stmts.push_back($$);
|
||||
}
|
||||
|
||||
| ';'
|
||||
|
|
|
@ -345,6 +345,7 @@ template<class T> int atoi_n(int len, const char* s, const char** end, int base,
|
|||
// Instantiate the ones we need.
|
||||
template int atoi_n<int>(int len, const char* s, const char** end, int base, int& result);
|
||||
template int atoi_n<int64_t>(int len, const char* s, const char** end, int base, int64_t& result);
|
||||
template int atoi_n<uint64_t>(int len, const char* s, const char** end, int base, uint64_t& result);
|
||||
|
||||
char* uitoa_n(uint64 value, char* str, int n, int base, const char* prefix)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue