Skip to content

Commit 28e53b0

Browse files
authored
Update agents.py
1 parent 4e9b522 commit 28e53b0

1 file changed

Lines changed: 155 additions & 1 deletion

File tree

  • gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/agents

gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/agents/agents.py

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
from datetime import datetime
77
from typing import Dict
88

9+
import time
10+
import os
11+
from functools import wraps
12+
import sys
13+
import inspect
14+
import atexit
15+
916
from cimgraph.databases import ConnectionParameters
1017
from cimgraph.databases.gridappsd import GridappsdConnection
1118
from cimgraph.models import FeederModel
@@ -17,12 +24,18 @@
1724
from gridappsd_field_bus.field_interface.gridappsd_field_bus import GridAPPSDMessageBus
1825
from gridappsd_field_bus.field_interface.interfaces import (FieldMessageBus, MessageBusDefinition, MessageBusFactory)
1926

27+
2028
CIM_PROFILE = None
2129
IEC61970_301 = None
2230
cim = None
2331

2432
_log = logging.getLogger(__name__)
25-
33+
decorator_logger = logging.getLogger("decorator_logger")
34+
decorator_logger.setLevel(logging.INFO)
35+
file_handler = logging.FileHandler("compute_req_log.txt") # Log file name
36+
formatter = logging.Formatter('[COMPUTE_REQ] %(asctime)s - %(message)s')
37+
file_handler.setFormatter(formatter)
38+
decorator_logger.addHandler(file_handler)
2639

2740
def set_cim_profile(cim_profile: str, iec61970_301: int):
2841
global CIM_PROFILE
@@ -41,6 +54,147 @@ class AgentRegistrationDetails:
4154
upstream_message_bus_id: FieldMessageBus.id
4255
downstream_message_bus_id: FieldMessageBus.id
4356

57+
@atexit.register
58+
def call_counter_report():
59+
decorator_logger.info("Function call counts summary:")
60+
for func_name, count in function_call_counts.items():
61+
decorator_logger.info(f"{func_name} was called {count} time(s)")
62+
63+
@atexit.register
64+
def message_size_report():
65+
decorator_logger.info("Total message size summary:")
66+
for func_name, total_size in message_size_totals.items():
67+
decorator_logger.info(f"{func_name} total message size: {total_size} bytes")
68+
69+
def compute_req(cls):
70+
functions = [
71+
'__init__',
72+
#'on_measurement',
73+
'on_upstream_message',
74+
'on_downstream_message',
75+
'on_request',
76+
'publish_upstream',
77+
'publish_downstream',
78+
'send_control_command'
79+
]
80+
81+
def call_counter(func):
82+
name = func.__qualname__
83+
84+
@wraps(func)
85+
def wrapper(*args, **kwargs):
86+
if args[0].agent_id+'.'+name not in function_call_counts:
87+
function_call_counts[args[0].agent_id+'.'+name] = 0
88+
function_call_counts[args[0].agent_id+'.'+name] += 1
89+
#decorator_logger.info(f"{name} called {function_call_counts[name]} times")
90+
return func(*args, **kwargs)
91+
return wrapper
92+
93+
def timed(func):
94+
@wraps(func)
95+
def wrapper(*args, **kwargs):
96+
start = time.perf_counter()
97+
result = func(*args, **kwargs)
98+
end = time.perf_counter()
99+
class_name = args[0].__class__.__name__ if args else ""
100+
if func.__name__ == '__init__':
101+
decorator_logger.info(f"{class_name}.{func.__name__}.{args[0].agent_id} took: {end - start:.6f} seconds")
102+
return result
103+
return wrapper
104+
105+
def get_deep_size(func):
106+
@wraps(func)
107+
def wrapper(*args, **kwargs):
108+
result = func(*args, **kwargs)
109+
110+
def deep_size(obj, seen=None):
111+
if seen is None:
112+
seen = set()
113+
obj_id = id(obj)
114+
if obj_id in seen:
115+
return 0
116+
seen.add(obj_id)
117+
size = sys.getsizeof(obj)
118+
if isinstance(obj, dict):
119+
size += sum(deep_size(k, seen) + deep_size(v, seen) for k, v in obj.items())
120+
elif isinstance(obj, (list, tuple, set, frozenset)):
121+
size += sum(deep_size(i, seen) for i in obj)
122+
elif hasattr(obj, '__dict__'):
123+
for attr_name, attr_value in vars(obj).items():
124+
if attr_name in ['feeder_area', 'switch_area', 'secondary_area']:
125+
continue
126+
size += deep_size(attr_value, seen)
127+
elif hasattr(obj, '__slots__'):
128+
size += sum(deep_size(getattr(obj, slot), seen) for slot in obj.__slots__ if hasattr(obj, slot))
129+
return size
130+
131+
self = args[0]
132+
obj_size = deep_size(self)
133+
decorator_logger.info(f"{self.__class__.__name__}.{func.__name__}.{args[0].agent_id} size is: {obj_size} bytes")
134+
135+
return result
136+
return wrapper
137+
138+
def get_graph_size(func):
139+
@wraps(func)
140+
def wrapper(*args, **kwargs):
141+
self = args[0]
142+
result = func(*args, **kwargs)
143+
area_names = ['feeder_area', 'switch_area', 'secondary_area']
144+
area_found = False
145+
for name in area_names:
146+
area_dict = getattr(self, name, None)
147+
if area_dict is not None and hasattr(area_dict, 'graph'):
148+
graph_keys = [key.__name__ for key in list(area_dict.graph.keys())]
149+
size = len(area_dict.graph.keys())
150+
decorator_logger.info(f"{self.__class__.__name__}.{func.__name__}.{args[0].agent_id} length of graph: {size}")
151+
decorator_logger.info(f"{self.__class__.__name__}.{name}.{args[0].agent_id} graph keys: {graph_keys}")
152+
area_found = True
153+
break
154+
155+
if not area_found:
156+
decorator_logger.error(f"{class_name}.{func.__name__}.{args[0].agent_id} No area dictionary (feeder/switch/secondary) found in {self.__class__.__name__}")
157+
return result
158+
return wrapper
159+
160+
def log_message_size(func):
161+
name = func.__qualname__
162+
163+
@wraps(func)
164+
def wrapper(*args, **kwargs):
165+
sig = inspect.signature(func)
166+
bound_args = sig.bind(*args, **kwargs)
167+
bound_args.apply_defaults()
168+
169+
if 'message' in bound_args.arguments:
170+
msg = bound_args.arguments['message']
171+
size = sys.getsizeof(msg)
172+
if args[0].agent_id+'.'+name not in message_size_totals:
173+
message_size_totals[args[0].agent_id+'.'+name] = 0
174+
message_size_totals[args[0].agent_id+'.'+name] += size
175+
176+
if 'differenceBuilder' in bound_args.arguments:
177+
msg = bound_args.arguments['differenceBuilder']
178+
size = sys.getsizeof(msg)
179+
if args[0].agent_id+'.'+name not in message_size_totals:
180+
message_size_totals[args[0].agent_id+'.'+name] = 0
181+
message_size_totals[args[0].agent_id+'.'+name] += size
182+
183+
return func(*args, **kwargs)
184+
return wrapper
185+
186+
# Decorate the relevant functions
187+
for attr_name in functions:
188+
if hasattr(cls, attr_name):
189+
original_func = getattr(cls, attr_name)
190+
if callable(original_func):
191+
if attr_name == '__init__':
192+
decorated = get_deep_size(get_graph_size(timed(original_func)))
193+
else:
194+
decorated = call_counter(log_message_size(timed(original_func)))
195+
setattr(cls, attr_name, decorated)
196+
197+
return cls
44198

45199
class DistributedAgent:
46200

0 commit comments

Comments
 (0)