mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
optionally hash original, not extended, form of records for profiling
profile types associated with global initializations incorporate type name, if present, into type hash
This commit is contained in:
parent
0f18a01bf7
commit
0b45ff2179
3 changed files with 99 additions and 18 deletions
|
@ -59,13 +59,16 @@ p_hash_type script_specific_hash(const StmtPtr& body, p_hash_type generic_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ProfileFunc::ProfileFunc(const Func* func, const StmtPtr& body)
|
ProfileFunc::ProfileFunc(const Func* func, const StmtPtr& body, bool _abs_rec_fields)
|
||||||
{
|
{
|
||||||
|
abs_rec_fields = _abs_rec_fields;
|
||||||
Profile(func->GetType().get(), body);
|
Profile(func->GetType().get(), body);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileFunc::ProfileFunc(const Expr* e)
|
ProfileFunc::ProfileFunc(const Expr* e, bool _abs_rec_fields)
|
||||||
{
|
{
|
||||||
|
abs_rec_fields = _abs_rec_fields;
|
||||||
|
|
||||||
if ( e->Tag() == EXPR_LAMBDA )
|
if ( e->Tag() == EXPR_LAMBDA )
|
||||||
{
|
{
|
||||||
auto func = e->AsLambdaExpr();
|
auto func = e->AsLambdaExpr();
|
||||||
|
@ -227,10 +230,16 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e)
|
||||||
}
|
}
|
||||||
|
|
||||||
case EXPR_FIELD:
|
case EXPR_FIELD:
|
||||||
{
|
if ( abs_rec_fields )
|
||||||
auto f = e->AsFieldExpr()->Field();
|
{
|
||||||
addl_hashes.push_back(p_hash(f));
|
auto f = e->AsFieldExpr()->Field();
|
||||||
}
|
addl_hashes.push_back(p_hash(f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto fn = e->AsFieldExpr()->FieldName();
|
||||||
|
addl_hashes.push_back(p_hash(fn));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_ASSIGN:
|
case EXPR_ASSIGN:
|
||||||
|
@ -405,14 +414,18 @@ void ProfileFunc::TrackID(const ID* id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ProfileFuncs::ProfileFuncs(std::vector<FuncInfo>& funcs, is_compilable_pred pred)
|
ProfileFuncs::ProfileFuncs(std::vector<FuncInfo>& funcs,
|
||||||
|
is_compilable_pred pred, bool _full_record_hashes)
|
||||||
{
|
{
|
||||||
|
full_record_hashes = _full_record_hashes;
|
||||||
|
|
||||||
for ( auto& f : funcs )
|
for ( auto& f : funcs )
|
||||||
{
|
{
|
||||||
if ( f.ShouldSkip() )
|
if ( f.ShouldSkip() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto pf = std::make_unique<ProfileFunc>(f.Func(), f.Body());
|
auto pf = std::make_unique<ProfileFunc>(f.Func(), f.Body(),
|
||||||
|
full_record_hashes);
|
||||||
|
|
||||||
if ( ! pred || (*pred)(pf.get()) )
|
if ( ! pred || (*pred)(pf.get()) )
|
||||||
MergeInProfile(pf.get());
|
MergeInProfile(pf.get());
|
||||||
|
@ -442,7 +455,19 @@ ProfileFuncs::ProfileFuncs(std::vector<FuncInfo>& funcs, is_compilable_pred pred
|
||||||
void ProfileFuncs::MergeInProfile(ProfileFunc* pf)
|
void ProfileFuncs::MergeInProfile(ProfileFunc* pf)
|
||||||
{
|
{
|
||||||
all_globals.insert(pf->AllGlobals().begin(), pf->AllGlobals().end());
|
all_globals.insert(pf->AllGlobals().begin(), pf->AllGlobals().end());
|
||||||
globals.insert(pf->Globals().begin(), pf->Globals().end());
|
|
||||||
|
for ( auto& g : pf->Globals() )
|
||||||
|
{
|
||||||
|
if ( globals.count(g) > 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
globals.insert(g);
|
||||||
|
|
||||||
|
auto& v = g->GetVal();
|
||||||
|
if ( v )
|
||||||
|
main_types.push_back(v->GetType().get());
|
||||||
|
}
|
||||||
|
|
||||||
constants.insert(pf->Constants().begin(), pf->Constants().end());
|
constants.insert(pf->Constants().begin(), pf->Constants().end());
|
||||||
main_types.insert(main_types.end(),
|
main_types.insert(main_types.end(),
|
||||||
pf->OrderedTypes().begin(), pf->OrderedTypes().end());
|
pf->OrderedTypes().begin(), pf->OrderedTypes().end());
|
||||||
|
@ -471,7 +496,7 @@ void ProfileFuncs::DrainPendingExprs()
|
||||||
|
|
||||||
for ( auto e : pe )
|
for ( auto e : pe )
|
||||||
{
|
{
|
||||||
auto pf = std::make_shared<ProfileFunc>(e);
|
auto pf = std::make_shared<ProfileFunc>(e, full_record_hashes);
|
||||||
|
|
||||||
expr_profs[e] = pf;
|
expr_profs[e] = pf;
|
||||||
MergeInProfile(pf.get());
|
MergeInProfile(pf.get());
|
||||||
|
@ -575,6 +600,8 @@ p_hash_type ProfileFuncs::HashType(const Type* t)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto h = p_hash(t->Tag());
|
auto h = p_hash(t->Tag());
|
||||||
|
if ( ! tn.empty() )
|
||||||
|
h = merge_p_hashes(h, p_hash(tn));
|
||||||
|
|
||||||
// Enter an initial value for this type's hash. We'll update it
|
// Enter an initial value for this type's hash. We'll update it
|
||||||
// at the end, but having it here first will prevent recursive
|
// at the end, but having it here first will prevent recursive
|
||||||
|
@ -611,13 +638,30 @@ p_hash_type ProfileFuncs::HashType(const Type* t)
|
||||||
{
|
{
|
||||||
const auto& ft = t->AsRecordType();
|
const auto& ft = t->AsRecordType();
|
||||||
auto n = ft->NumFields();
|
auto n = ft->NumFields();
|
||||||
|
auto orig_n = ft->NumOrigFields();
|
||||||
|
|
||||||
h = merge_p_hashes(h, p_hash("record"));
|
h = merge_p_hashes(h, p_hash("record"));
|
||||||
h = merge_p_hashes(h, p_hash(n));
|
|
||||||
|
if ( full_record_hashes )
|
||||||
|
h = merge_p_hashes(h, p_hash(n));
|
||||||
|
else
|
||||||
|
h = merge_p_hashes(h, p_hash(orig_n));
|
||||||
|
|
||||||
for ( auto i = 0; i < n; ++i )
|
for ( auto i = 0; i < n; ++i )
|
||||||
{
|
{
|
||||||
|
bool do_hash = full_record_hashes;
|
||||||
|
if ( ! do_hash )
|
||||||
|
do_hash = (i < orig_n);
|
||||||
|
|
||||||
const auto& f = ft->FieldDecl(i);
|
const auto& f = ft->FieldDecl(i);
|
||||||
|
auto type_h = HashType(f->type);
|
||||||
|
|
||||||
|
if ( do_hash )
|
||||||
|
{
|
||||||
|
h = merge_p_hashes(h, p_hash(f->id));
|
||||||
|
h = merge_p_hashes(h, type_h);
|
||||||
|
}
|
||||||
|
|
||||||
h = merge_p_hashes(h, p_hash(f->id));
|
h = merge_p_hashes(h, p_hash(f->id));
|
||||||
h = merge_p_hashes(h, HashType(f->type));
|
h = merge_p_hashes(h, HashType(f->type));
|
||||||
|
|
||||||
|
@ -626,7 +670,8 @@ p_hash_type ProfileFuncs::HashType(const Type* t)
|
||||||
|
|
||||||
if ( f->attrs )
|
if ( f->attrs )
|
||||||
{
|
{
|
||||||
h = merge_p_hashes(h, p_hash(f->attrs));
|
if ( do_hash )
|
||||||
|
h = merge_p_hashes(h, HashAttrs(f->attrs));
|
||||||
AnalyzeAttrs(f->attrs.get());
|
AnalyzeAttrs(f->attrs.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -702,6 +747,29 @@ p_hash_type ProfileFuncs::HashType(const Type* t)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p_hash_type ProfileFuncs::HashAttrs(const AttributesPtr& Attrs)
|
||||||
|
{
|
||||||
|
// It's tempting to just use p_hash, but that won't work
|
||||||
|
// if the attributes wind up with extensible records in their
|
||||||
|
// descriptions, if we're not doing full record hashes.
|
||||||
|
auto attrs = Attrs->GetAttrs();
|
||||||
|
p_hash_type h = 0;
|
||||||
|
|
||||||
|
for ( const auto& a : attrs )
|
||||||
|
{
|
||||||
|
h = merge_p_hashes(h, p_hash(a->Tag()));
|
||||||
|
auto e = a->GetExpr();
|
||||||
|
|
||||||
|
// We don't try to hash an associated expression, since those
|
||||||
|
// can vary in structure due to compilation of elements. We
|
||||||
|
// do though enforce consistency for their types.
|
||||||
|
if ( e )
|
||||||
|
h = merge_p_hashes(h, HashType(e->GetType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
void ProfileFuncs::AnalyzeAttrs(const Attributes* Attrs)
|
void ProfileFuncs::AnalyzeAttrs(const Attributes* Attrs)
|
||||||
{
|
{
|
||||||
auto attrs = Attrs->GetAttrs();
|
auto attrs = Attrs->GetAttrs();
|
||||||
|
|
|
@ -84,13 +84,13 @@ class ProfileFunc : public TraversalCallback {
|
||||||
public:
|
public:
|
||||||
// Constructor used for the usual case of profiling a script
|
// Constructor used for the usual case of profiling a script
|
||||||
// function and one of its bodies.
|
// function and one of its bodies.
|
||||||
ProfileFunc(const Func* func, const StmtPtr& body);
|
ProfileFunc(const Func* func, const StmtPtr& body, bool abs_rec_fields);
|
||||||
|
|
||||||
// Constructor for profiling an AST expression. This exists
|
// Constructor for profiling an AST expression. This exists
|
||||||
// to support (1) profiling lambda expressions, and (2) traversing
|
// to support (1) profiling lambda expressions, and (2) traversing
|
||||||
// attribute expressions (such as &default=expr) to discover what
|
// attribute expressions (such as &default=expr) to discover what
|
||||||
// components they include.
|
// components they include.
|
||||||
ProfileFunc(const Expr* func);
|
ProfileFunc(const Expr* func, bool abs_rec_fields);
|
||||||
|
|
||||||
// See the comments for the associated member variables for each
|
// See the comments for the associated member variables for each
|
||||||
// of these accessors.
|
// of these accessors.
|
||||||
|
@ -263,6 +263,10 @@ protected:
|
||||||
// whether a given body contains any.
|
// whether a given body contains any.
|
||||||
int num_when_stmts = 0;
|
int num_when_stmts = 0;
|
||||||
|
|
||||||
|
// Whether we should treat record field accesses as absolute
|
||||||
|
// (integer offset) or relative (name-based).
|
||||||
|
bool abs_rec_fields;
|
||||||
|
|
||||||
// Whether we're separately processing a "when" condition to
|
// Whether we're separately processing a "when" condition to
|
||||||
// mine out its script calls.
|
// mine out its script calls.
|
||||||
bool in_when = false;
|
bool in_when = false;
|
||||||
|
@ -280,8 +284,11 @@ public:
|
||||||
// Updates entries in "funcs" to include profiles. If pred is
|
// Updates entries in "funcs" to include profiles. If pred is
|
||||||
// non-nil, then it is called for each profile to see whether it's
|
// non-nil, then it is called for each profile to see whether it's
|
||||||
// compilable, and, if not, the FuncInfo is marked as ShouldSkip().
|
// compilable, and, if not, the FuncInfo is marked as ShouldSkip().
|
||||||
|
// "full_record_hashes" controls whether the hashes for extended
|
||||||
|
// records covers their final, full form, or should only their
|
||||||
|
// original fields.
|
||||||
ProfileFuncs(std::vector<FuncInfo>& funcs,
|
ProfileFuncs(std::vector<FuncInfo>& funcs,
|
||||||
is_compilable_pred pred = nullptr);
|
is_compilable_pred pred, bool full_record_hashes);
|
||||||
|
|
||||||
// The following accessors provide a global profile across all of
|
// The following accessors provide a global profile across all of
|
||||||
// the (non-skipped) functions in "funcs". See the comments for
|
// the (non-skipped) functions in "funcs". See the comments for
|
||||||
|
@ -326,6 +333,8 @@ public:
|
||||||
p_hash_type HashType(const TypePtr& t) { return HashType(t.get()); }
|
p_hash_type HashType(const TypePtr& t) { return HashType(t.get()); }
|
||||||
p_hash_type HashType(const Type* t);
|
p_hash_type HashType(const Type* t);
|
||||||
|
|
||||||
|
p_hash_type HashAttrs(const AttributesPtr& attrs);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Incorporate the given function profile into the global profile.
|
// Incorporate the given function profile into the global profile.
|
||||||
void MergeInProfile(ProfileFunc* pf);
|
void MergeInProfile(ProfileFunc* pf);
|
||||||
|
@ -414,6 +423,10 @@ protected:
|
||||||
// profile. These can arise for example due to lambdas or
|
// profile. These can arise for example due to lambdas or
|
||||||
// record attributes.
|
// record attributes.
|
||||||
std::vector<const Expr*> pending_exprs;
|
std::vector<const Expr*> pending_exprs;
|
||||||
|
|
||||||
|
// Whether the hashes for extended records should cover their final,
|
||||||
|
// full form, or only their original fields.
|
||||||
|
bool full_record_hashes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ void optimize_func(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf,
|
||||||
|
|
||||||
if ( analysis_options.optimize_AST )
|
if ( analysis_options.optimize_AST )
|
||||||
{
|
{
|
||||||
pf = std::make_shared<ProfileFunc>(f, body);
|
pf = std::make_shared<ProfileFunc>(f, body, true);
|
||||||
body->Traverse(pf.get());
|
body->Traverse(pf.get());
|
||||||
|
|
||||||
RD_Decorate reduced_rds(pf);
|
RD_Decorate reduced_rds(pf);
|
||||||
|
@ -111,7 +111,7 @@ void optimize_func(ScriptFunc* f, std::shared_ptr<ProfileFunc> pf,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile the new body.
|
// Profile the new body.
|
||||||
pf = std::make_shared<ProfileFunc>(f, body);
|
pf = std::make_shared<ProfileFunc>(f, body, true);
|
||||||
body->Traverse(pf.get());
|
body->Traverse(pf.get());
|
||||||
|
|
||||||
// Compute its reaching definitions.
|
// Compute its reaching definitions.
|
||||||
|
@ -224,7 +224,7 @@ void analyze_scripts()
|
||||||
|
|
||||||
// Now that everything's parsed and BiF's have been initialized,
|
// Now that everything's parsed and BiF's have been initialized,
|
||||||
// profile the functions.
|
// profile the functions.
|
||||||
auto pfs = std::make_unique<ProfileFuncs>(funcs);
|
auto pfs = std::make_unique<ProfileFuncs>(funcs, nullptr, true);
|
||||||
|
|
||||||
// Figure out which functions either directly or indirectly
|
// Figure out which functions either directly or indirectly
|
||||||
// appear in "when" clauses.
|
// appear in "when" clauses.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue