Add a function ‘valueSize’
It returns the size of value, including all other values and environments reachable from it. It is intended for debugging memory consumption issues.
This commit is contained in:
		
							parent
							
								
									68cf98c4d2
								
							
						
					
					
						commit
						eff120d1b9
					
				
					 4 changed files with 99 additions and 2 deletions
				
			
		|  | @ -404,9 +404,12 @@ Value * EvalState::allocValue() | ||||||
| 
 | 
 | ||||||
| Env & EvalState::allocEnv(unsigned int size) | Env & EvalState::allocEnv(unsigned int size) | ||||||
| { | { | ||||||
|  |     assert(size <= std::numeric_limits<decltype(Env::size)>::max()); | ||||||
|  | 
 | ||||||
|     nrEnvs++; |     nrEnvs++; | ||||||
|     nrValuesInEnvs += size; |     nrValuesInEnvs += size; | ||||||
|     Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *)); |     Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *)); | ||||||
|  |     env->size = size; | ||||||
| 
 | 
 | ||||||
|     /* Clear the values because maybeThunk() and lookupVar fromWith expects this. */ |     /* Clear the values because maybeThunk() and lookupVar fromWith expects this. */ | ||||||
|     for (unsigned i = 0; i < size; ++i) |     for (unsigned i = 0; i < size; ++i) | ||||||
|  | @ -1488,4 +1491,81 @@ void EvalState::printCanaries() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | size_t valueSize(Value & v) | ||||||
|  | { | ||||||
|  |     std::set<const void *> seen; | ||||||
|  | 
 | ||||||
|  |     auto doString = [&](const char * s) -> size_t { | ||||||
|  |         if (seen.find(s) != seen.end()) return 0; | ||||||
|  |         seen.insert(s); | ||||||
|  |         return strlen(s) + 1; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     std::function<size_t(Value & v)> doValue; | ||||||
|  |     std::function<size_t(Env & v)> doEnv; | ||||||
|  | 
 | ||||||
|  |     doValue = [&](Value & v) -> size_t { | ||||||
|  |         if (seen.find(&v) != seen.end()) return 0; | ||||||
|  |         seen.insert(&v); | ||||||
|  | 
 | ||||||
|  |         size_t sz = sizeof(Value); | ||||||
|  | 
 | ||||||
|  |         switch (v.type) { | ||||||
|  |         case tString: | ||||||
|  |             sz += doString(v.string.s); | ||||||
|  |             if (v.string.context) | ||||||
|  |                 for (const char * * p = v.string.context; *p; ++p) | ||||||
|  |                     sz += doString(*p); | ||||||
|  |             break; | ||||||
|  |         case tPath: | ||||||
|  |             sz += doString(v.path); | ||||||
|  |             break; | ||||||
|  |         case tAttrs: | ||||||
|  |             for (auto & i : *v.attrs) | ||||||
|  |                 sz += doValue(*i.value); | ||||||
|  |             break; | ||||||
|  |         case tList: | ||||||
|  |             for (unsigned int n = 0; n < v.list.length; ++n) | ||||||
|  |                 sz += doValue(*v.list.elems[n]); | ||||||
|  |             break; | ||||||
|  |         case tThunk: | ||||||
|  |             sz += doEnv(*v.thunk.env); | ||||||
|  |             break; | ||||||
|  |         case tApp: | ||||||
|  |             sz += doValue(*v.app.left); | ||||||
|  |             sz += doValue(*v.app.right); | ||||||
|  |             break; | ||||||
|  |         case tLambda: | ||||||
|  |             sz += doEnv(*v.lambda.env); | ||||||
|  |             break; | ||||||
|  |         case tPrimOpApp: | ||||||
|  |             sz += doValue(*v.primOpApp.left); | ||||||
|  |             sz += doValue(*v.primOpApp.right); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             ; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return sz; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     doEnv = [&](Env & env) -> size_t { | ||||||
|  |         if (seen.find(&env) != seen.end()) return 0; | ||||||
|  |         seen.insert(&env); | ||||||
|  | 
 | ||||||
|  |         size_t sz = sizeof(Env); | ||||||
|  | 
 | ||||||
|  |         for (unsigned int i = 0; i < env.size; ++i) | ||||||
|  |             if (env.values[i]) | ||||||
|  |                 sz += doValue(*env.values[i]); | ||||||
|  | 
 | ||||||
|  |         if (env.up) sz += doEnv(*env.up); | ||||||
|  | 
 | ||||||
|  |         return sz; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return doValue(v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -95,8 +95,9 @@ struct PrimOp | ||||||
| struct Env | struct Env | ||||||
| { | { | ||||||
|     Env * up; |     Env * up; | ||||||
|     unsigned short prevWith; // nr of levels up to next `with' environment
 |     unsigned short size; // used by ‘valueSize’
 | ||||||
|     bool haveWithAttrs; |     unsigned short prevWith:15; // nr of levels up to next `with' environment
 | ||||||
|  |     unsigned short haveWithAttrs:1; | ||||||
|     Value * values[0]; |     Value * values[0]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -423,6 +423,13 @@ void prim_gcCanary(EvalState & state, const Pos & pos, Value * * args, Value & v | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | void prim_valueSize(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||||
|  | { | ||||||
|  |     /* We're not forcing the argument on purpose. */ | ||||||
|  |     mkInt(v, valueSize(*args[0])); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /*************************************************************
 | /*************************************************************
 | ||||||
|  * Derivations |  * Derivations | ||||||
|  *************************************************************/ |  *************************************************************/ | ||||||
|  | @ -1416,8 +1423,11 @@ void EvalState::createBaseEnv() | ||||||
|     addPrimOp("__addErrorContext", 2, prim_addErrorContext); |     addPrimOp("__addErrorContext", 2, prim_addErrorContext); | ||||||
|     addPrimOp("__tryEval", 1, prim_tryEval); |     addPrimOp("__tryEval", 1, prim_tryEval); | ||||||
|     addPrimOp("__getEnv", 1, prim_getEnv); |     addPrimOp("__getEnv", 1, prim_getEnv); | ||||||
|  | 
 | ||||||
|  |     // Debugging
 | ||||||
|     addPrimOp("__trace", 2, prim_trace); |     addPrimOp("__trace", 2, prim_trace); | ||||||
|     addPrimOp("__gcCanary", 1, prim_gcCanary); |     addPrimOp("__gcCanary", 1, prim_gcCanary); | ||||||
|  |     addPrimOp("__valueSize", 1, prim_valueSize); | ||||||
| 
 | 
 | ||||||
|     // Paths
 |     // Paths
 | ||||||
|     addPrimOp("__toPath", 1, prim_toPath); |     addPrimOp("__toPath", 1, prim_toPath); | ||||||
|  |  | ||||||
|  | @ -159,4 +159,10 @@ static inline void mkPathNoCopy(Value & v, const char * s) | ||||||
| void mkPath(Value & v, const char * s); | void mkPath(Value & v, const char * s); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | /* Compute the size in bytes of the given value, including all values
 | ||||||
|  |    and environments reachable from it. Static expressions (Exprs) are | ||||||
|  |    not included. */ | ||||||
|  | size_t valueSize(Value & v); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue