Commit 9b4201c5 authored by Sam Guyer's avatar Sam Guyer
Browse files

New repository

parent 02b89d45
FLAGS=-O2
simulator: simulator.o execution.o heap.o classinfo.o tokenizer.o analyze.o
g++ $(FLAGS) -o simulator simulator.o execution.o heap.o classinfo.o tokenizer.o analyze.o
simulator.o: simulator.cpp classinfo.h tokenizer.h
g++ $(FLAGS) -c simulator.cpp
analyze.o: analyze.cpp classinfo.h tokenizer.h
g++ $(FLAGS) -c analyze.cpp
execution.o: execution.cpp classinfo.h tokenizer.h
g++ $(FLAGS) -c execution.cpp
heap.o: heap.cpp classinfo.h tokenizer.h
g++ $(FLAGS) -c heap.cpp
classinfo.o: classinfo.cpp classinfo.h tokenizer.h
g++ $(FLAGS) -c classinfo.cpp
tokenizer.o: tokenizer.cpp classinfo.h tokenizer.h
g++ $(FLAGS) -c tokenizer.cpp
clean:
rm -f *.o simulator
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
#include <map>
#include <set>
#include <vector>
using namespace std;
#include "tokenizer.h"
#include "classinfo.h"
#include "execution.h"
#include "heap.h"
extern HeapState Heap;
extern ExecState Exec;
class Object;
class CCNode;
// -- Union/find over objects
class DisjointSets
{
private:
map<Object *, Object *> m_parent;
map<Object *, int> m_rank;
map<Object *, int> m_set_size;
public:
DisjointSets() {}
bool is_root(Object * x)
{
map<Object *, Object *>::iterator p = m_parent.find(x);
if (p != m_parent.end()) {
return (*p).second == x;
}
return false;
}
void make_set(Object * x)
{
if (m_parent.find(x) == m_parent.end()) {
m_parent[x] = x;
m_rank[x] = 0;
m_set_size[x] = 1;
}
}
Object * find(Object * x)
{
Object * p = m_parent[x];
if (p == x)
return x;
else {
Object * root = find(p);
m_parent[x] = root;
return root;
}
}
void setunion(Object * A, Object * B)
{
Object * A_root = find(A);
Object * B_root = find(B);
if (A_root == B_root)
return;
// -- Tree with the smaller rank becomes the child
int A_rank = m_rank[A_root];
int B_rank = m_rank[B_root];
if (A_rank < B_rank) {
// -- A is smaller; B becomes root
m_parent[A_root] = B_root;
m_set_size[B_root] += m_set_size[A_root];
} else {
if (A_rank > B_rank) {
// -- B is smaller; A becomes root
m_parent[B_root] = A_root;
m_set_size[A_root] += m_set_size[B_root];
} else {
// -- Tie; choose A as root
m_parent[B_root] = A_root;
m_rank[A_root]++;
m_set_size[A_root] += m_set_size[B_root];
}
}
}
void report()
{
for (map<Object *, int>::iterator i = m_set_size.begin();
i != m_set_size.end();
++i)
{
pair<Object *, int> entry = *i;
Object * obj = entry.first;
if (is_root(obj)) {
cout << "Set size " << entry.second << " root " << obj->info()
<< " lifetime " << (obj->getDeathTime() - obj->getCreateTime()) << endl;
}
}
}
void get_sets(map<Object *, set< Object *> > & the_sets)
{
for (map<Object *, int>::iterator i = m_set_size.begin();
i != m_set_size.end();
++i)
{
pair<Object *, int> entry = *i;
Object * obj = entry.first;
Object * root = find(obj);
the_sets[root].insert(obj);
}
}
};
double compute_overlap(unsigned int start1, unsigned int end1,
unsigned int start2, unsigned int end2)
{
unsigned int span_start = min(start1, start2);
unsigned int span_end = max(end1, end2);
unsigned int overlap_start = max(start1, start2);
unsigned int overlap_end = min(end1, end2);
double fspan = (double) (span_end - span_start);
double foverlap = (double) (overlap_end - overlap_start);
double frac = foverlap/fspan;
return frac * 100.0;
}
void analyze()
{
double total_time = (double) Exec.Now();
DisjointSets sets;
map<Object *, EdgeSet> strong_edges;
map<Object *, EdgeSet> weak_edges;
for (EdgeSet::iterator i = Heap.begin_edges();
i != Heap.end_edges();
++i)
{
Edge * edge = *i;
Object * source = edge->getSource();
Object * target = edge->getTarget();
// -- Compare lifetimes
// Invariants:
// CreateTime(edge) > CreateTime(source)
// CreateTime(edge) > CreateTime(target)
// EndTIme(edge) <= DeathTime(source)
// EndTime(edge) < DeathTime(target)
double source_overlap = compute_overlap(source->getCreateTime(), source->getDeathTime(),
edge->getCreateTime(), edge->getEndTime());
double target_overlap = compute_overlap(source->getCreateTime(), source->getDeathTime(),
target->getCreateTime(), target->getDeathTime());
unsigned int edge_lifetime = edge->getEndTime() - edge->getCreateTime();
double perc_lifetime = (((double) edge_lifetime)/total_time) * 100.0;
sets.make_set(source);
sets.make_set(target);
if (source_overlap > 0.9 and target_overlap > 0.9 /* and perc_lifetime > 0.1 */) {
sets.setunion(source, target);
strong_edges[source].insert(edge);
} else {
weak_edges[source].insert(edge);
}
/*
if (perc_lifetime > 0.1)
printf("Strength s->e %5.3f s->t %5.3f lifetime %5.5f \n",
source_overlap, target_overlap, perc_lifetime);
*/
}
map<Object *, set< Object *> > the_sets;
sets.get_sets(the_sets);
int num_small_sets = 0;
for (map<Object *, set< Object *> >::iterator j = the_sets.begin();
j != the_sets.end();
++j)
{
pair<Object * const, set<Object *> > & entry = *j;
set<Object *> & one_set = entry.second;
set<Object *> targets;
int out_edges = 0;
if (one_set.size() <= 5) {
num_small_sets++;
}
if (one_set.size() > 1000) {
for (set<Object *>::iterator k = one_set.begin();
k != one_set.end();
++k)
{
Object * obj = *k;
if (weak_edges.find(obj) != weak_edges.end()) {
EdgeSet & weak = weak_edges[obj];
for (EdgeSet::iterator m = weak.begin();
m != weak.end();
++m)
{
Edge * weak_edge = *m;
if (one_set.find(weak_edge->getTarget()) == one_set.end()) {
// printf("OUT-EDGE from %s to %s\n", weak_edge->getSource()->info().c_str(), weak_edge->getTarget()->info().c_str());
targets.insert(sets.find(weak_edge->getTarget()));
out_edges++;
}
}
}
}
cout << "Set with size " << one_set.size() << " has " << out_edges << " outgoing edges to " << targets.size() << " sets" << endl;
cout << " Root is " << entry.first->info() << " created " << entry.first->getCreateTime() << " died " << entry.first->getDeathTime() << endl;
for (set<Object *>::iterator n = targets.begin();
n != targets.end();
++n)
{
Object * target = *n;
cout << " Edge to set size " << the_sets[target].size() << " root " << target->info() << " created " << target->getCreateTime() << " died " << target->getDeathTime() << endl;
}
}
}
cout << "Total objects " << Heap.size() << endl;
cout << "Total sets " << the_sets.size() << endl;
cout << "Number small sets " << num_small_sets << endl;
// sets.report();
}
#include "classinfo.h"
#include "tokenizer.h"
#include <stdlib.h>
// -- Contents of the names file
ClassMap ClassInfo::TheClasses;
// -- All methods (also in the classes)
MethodMap ClassInfo::TheMethods;
// -- All fields (also in the classes)
FieldMap ClassInfo::TheFields;
// -- Allocation sites
AllocSiteMap ClassInfo::TheAllocSites;
// -- Debug flag
bool ClassInfo::debug_names = false;
// -- Read in the names file
void ClassInfo::read_names_file(const char * filename)
{
FILE * f = fopen(filename, "r");
if ( ! f) {
cout << "ERROR: Could not open " << filename << endl;
exit(-1);
}
Tokenizer t(f);
while ( ! t.isDone()) {
t.getLine();
if (t.isDone()) break;
switch (t.getChar(0)) {
case 'C':
case 'I':
{
// -- Class and interface entries
// C/I <id> <name> <other stuff>
// -- Lookup or create the class info...
Class * cls = 0;
ClassMap::iterator p = TheClasses.find(t.getInt(1));
if (p == TheClasses.end()) {
// -- Not found, make a new one
cls = new Class(t.getInt(1), t.getString(2), (t.getChar(0) == 'I'));
TheClasses[cls->getId()] = cls;
} else {
cls = (*p).second;
}
if (debug_names)
cout << "CLASS " << cls->getName() << " id = " << cls->getId() << endl;
// Superclass ID and interfaces are optional
if (t.numTokens() > 3)
cls->setSuperclassId(t.getInt(3));
// -- For now, ignore the rest (interfaces implemented)
}
break;
case 'N':
{
// N <id> <classid> <classname> <methodname> <descriptor> <flags S|I +N>
// 0 1 2 3 4 5 6
Class * cls = TheClasses[t.getInt(2)];
Method * m = new Method(t.getInt(1), cls, t.getString(4), t.getString(5), t.getString(6));
TheMethods[m->getId()] = m;
cls->addMethod(m);
if (debug_names)
cout << " + METHOD " << m->info() << endl;
}
break;
case 'F':
{
// F S/I <id> <name> <classid> <classname> <descriptor>
// 0 1 2 3 4 5 6
Class * cls = TheClasses[t.getInt(4)];
Field * fld = new Field(t.getInt(2), cls, t.getString(3), t.getString(6), (t.getChar(1) == 'S'));
TheFields[fld->getId()] = fld;
cls->addField(fld);
if (debug_names)
cout << " + FIELD" << fld->getName() << " id = " << fld->getId() << " in class " << cls->getName() << endl;
}
break;
case 'S':
{
// S <methodid> <classid> <id> <type> <dims>
// 0 1 2 3 4 5
Method * meth = TheMethods[t.getInt(1)];
AllocSite * as = new AllocSite(t.getInt(3), meth, t.getString(3), t.getString(4), t.getInt(5));
TheAllocSites[as->getId()] = as;
meth->addAllocSite(as);
if (debug_names)
cout << " + ALLOC " << as->getType() << " id = " << as->getId() << " in method " << meth->info() << endl;
}
break;
case 'E':
{
// -- No need to process this entry (end of a class)
}
break;
default:
cout << "ERROR: Unknown char " << t.getChar(0) << endl;
break;
}
}
}
// ----------------------------------------------------------------------
// Info methods (for debugging)
string Method::info()
{
stringstream ss;
ss << m_class->info() << "." << m_name << m_descriptor;
return ss.str();
}
string AllocSite::info()
{
stringstream ss;
ss << m_method->info() << ":" << m_id;
return ss.str();
}
#ifndef CLASSINFO_H
#define CLASSINFO_H
// ----------------------------------------------------------------------
// Representation of class info
//
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
#include <map>
#include <set>
#include <vector>
using namespace std;
class Class;
class Method;
class Field;
class AllocSite;
typedef map<unsigned int, Method *> MethodMap;
typedef map<unsigned int, Field *> FieldMap;
typedef map<unsigned int, Class *> ClassMap;
typedef map<unsigned int, AllocSite *> AllocSiteMap;
// -- Global info, including the big routine to read the names file
class ClassInfo
{
public:
// -- Contents of the names file
static ClassMap TheClasses;
// -- All methods (also in the classes)
static MethodMap TheMethods;
// -- All fields (also in the classes)
static FieldMap TheFields;
// -- Allocation sites
static AllocSiteMap TheAllocSites;
// -- Debug flag
static bool debug_names;
// -- Read the names file
static void read_names_file(const char * filename);
};
// -- Representation of classes
class Entity
{
protected:
unsigned int m_id;
string m_name;
public:
Entity()
: m_id(0),
m_name()
{}
Entity(unsigned int id, const string& name)
: m_id(id),
m_name(name)
{}
unsigned int getId() const { return m_id; }
const string& getName() const { return m_name; }
};
class Field : public Entity
{
private:
bool m_isStatic;
Class * m_class;
string m_descriptor;
public:
Field(unsigned int id, Class * cls, char * name, char * descriptor, bool isstatic)
: Entity(id, name),
m_isStatic(isstatic),
m_class(cls),
m_descriptor(descriptor)
{}
Class * getClass() const { return m_class; }
};
class AllocSite : public Entity
{
private:
Method * m_method;
string m_descriptor;
int m_dimensions;
public:
AllocSite(unsigned int id, Method * meth, char * name, char * descriptor, unsigned int dimensions)
: Entity(id, name),
m_method(meth),
m_descriptor(descriptor),
m_dimensions(dimensions)
{}
Method * getMethod() const { return m_method; }
const string& getType() const { return m_descriptor; }
string info();
};
class Method : public Entity
{
private:
Class * m_class;
string m_descriptor;
string m_flags;
AllocSiteMap m_allocsites;
public:
Method(unsigned int id, Class * cls, char * name, char * descriptor, char * flags)
: Entity(id, name),
m_class(cls),
m_descriptor(descriptor),
m_flags(flags)
{}
Class * getClass() const { return m_class; }
void addAllocSite(AllocSite * a) { m_allocsites[a->getId()] = a; }
string info();
};
class Class : public Entity
{
private:
unsigned int m_superclassId;
bool m_is_interface;
MethodMap m_methods;
FieldMap m_fields;
public:
Class(unsigned int id, const string& name, bool is_interface)
: Entity(id, name),
m_superclassId(0),
m_is_interface(is_interface)
{}
void setSuperclassId(unsigned int sid) { m_superclassId = sid; }
void addMethod(Method * m) { m_methods[m->getId()] = m; }
void addField(Field * f) { m_fields[f->getId()] = f; }
string info()
{
return m_name;
}
};
#endif
// ----------------------------------------------------------------------
// Representation of runtime execution
// stacks, threads, time
#include "execution.h"
// ----------------------------------------------------------------------
// Calling context tree
CCNode * CCNode::Call(Method * m)
{
CCNode * result = 0;
CCMap::iterator p = m_callees.find(m->getId());
if (p == m_callees.end()) {
result = new CCNode(this, m);
m_callees[m->getId()] = result;
} else {
result = (*p).second;
}
return result;
}
CCNode * CCNode::Return(Method * m)
{
if (m_method != m) {
cout << "WEIRD: Returning from the wrong method " << m->info() << endl;
cout << "WEIRD: should be " << m_method->info() << endl;
}
return m_parent;
}
string CCNode::info()
{
stringstream ss;
if (m_method)
ss << m_method->info(); // << "@" << m_startTime;
else
ss << "ROOT";
return ss.str();
}
string CCNode::stacktrace()
{
stringstream ss;
CCNode * cur = this;
while (cur) {
ss << cur->info() << endl;
cur = cur->getParent();
}
return ss.str();
}