Commit 69abce9a authored by Shane Hathaway's avatar Shane Hathaway

Merged shane-activity-monitoring-branch.

parent 1b063f12
......@@ -11,7 +11,7 @@
#
##############################################################################
__doc__="""System management components"""
__version__='$Revision: 1.78 $'[11:-2]
__version__='$Revision: 1.79 $'[11:-2]
import sys,os,time,Globals, Acquisition, os, Undo
......@@ -49,6 +49,8 @@ class DatabaseManager(Fake, SimpleItem.Item, Acquisition.Implicit):
(
{'label':'Database', 'action':'manage_main',
'help':('OFSP','Database-Management_Database.stx')},
{'label':'Activity', 'action':'manage_activity',
'help':('OFSP','Database-Management_Activity.stx')},
{'label':'Cache Parameters', 'action':'manage_cacheParameters',
'help':('OFSP','Database-Management_Cache-Parameters.stx')},
{'label':'Flush Cache', 'action':'manage_cacheGC',
......@@ -58,6 +60,7 @@ class DatabaseManager(Fake, SimpleItem.Item, Acquisition.Implicit):
# These need to be here rather to make tabs work correctly. This
# needs to be revisited.
manage_activity=Globals.DTMLFile('dtml/activity', globals())
manage_cacheParameters=Globals.DTMLFile('dtml/cacheParameters', globals())
manage_cacheGC=Globals.DTMLFile('dtml/cacheGC', globals())
......
......@@ -13,10 +13,11 @@
__doc__='''Cache management support
$Id: CacheManager.py,v 1.24 2002/03/27 10:14:00 htrd Exp $'''
__version__='$Revision: 1.24 $'[11:-2]
$Id: CacheManager.py,v 1.25 2002/06/10 20:20:43 shane Exp $'''
__version__='$Revision: 1.25 $'[11:-2]
import Globals, time, sys
from DateTime import DateTime
class CacheManager:
"""Cache management mix-in
......@@ -25,10 +26,15 @@ class CacheManager:
_cache_size=400
_vcache_age=60
_vcache_size=400
_history_length = 3600 # Seconds
manage_cacheParameters=Globals.DTMLFile('dtml/cacheParameters', globals())
manage_cacheGC=Globals.DTMLFile('dtml/cacheGC', globals())
transparent_bar = Globals.ImageFile('www/transparent_bar.gif', globals())
store_bar = Globals.ImageFile('www/store_bar.gif', globals())
load_bar = Globals.ImageFile('www/load_bar.gif', globals())
def cache_length(self):
try: db=self._p_jar.db()
except:
......@@ -185,6 +191,9 @@ class CacheManager:
db.setCacheDeactivateAfter(self._cache_age)
db.setVersionCacheSize(self._vcache_size)
db.setVersionCacheDeactivateAfter(self._vcache_age)
am = self._getActivityMonitor()
if am is not None:
am.setHistoryLength(self._history_length)
def cache_detail(self, REQUEST=None):
"""
......@@ -239,5 +248,118 @@ class CacheManager:
# raw
return detail
def _getActivityMonitor(self):
db = self._p_jar.db()
if not hasattr(db, 'getActivityMonitor'):
return None
am = db.getActivityMonitor()
if am is None:
return None
return am
def getHistoryLength(self):
am = self._getActivityMonitor()
if am is None:
return 0
return am.getHistoryLength()
def manage_setHistoryLength(self, length, REQUEST=None):
"""Change the length of the activity monitor history.
"""
am = self._getActivityMonitor()
length = int(length)
if length < 0:
raise ValueError, 'length can not be negative'
if am is not None:
am.setHistoryLength(length)
self._history_length = length # Restore on startup
if REQUEST is not None:
response = REQUEST['RESPONSE']
response.redirect(REQUEST['URL1'] + '/manage_activity')
def getActivityChartData(self, segment_height, REQUEST=None):
"""Returns information for generating an activity chart.
"""
am = self._getActivityMonitor()
if am is None:
return None
if REQUEST is not None:
start = float(REQUEST.get('chart_start', 0))
end = float(REQUEST.get('chart_end', 0))
divisions = int(REQUEST.get('chart_divisions', 10))
analysis = am.getActivityAnalysis(start, end, divisions)
else:
analysis = am.getActivityAnalysis()
total_load_count = 0
total_store_count = 0
limit = 0
divs = []
for div in analysis:
total_store_count = total_store_count + div['stores']
total_load_count = total_load_count + div['loads']
sum = div['stores'] + div['loads']
if sum > limit:
limit = sum
if analysis:
segment_time = analysis[0]['end'] - analysis[0]['start']
else:
segment_time = 0
for div in analysis:
stores = div['stores']
if stores > 0:
store_len = max(int(segment_height * stores / limit), 1)
else:
store_len = 0
loads = div['loads']
if loads > 0:
load_len = max(int(segment_height * loads / limit), 1)
else:
load_len = 0
t = div['end'] - analysis[-1]['end'] # Show negative numbers.
if segment_time >= 3600:
# Show hours.
time_offset = '%dh' % (t / 3600)
elif segment_time >= 60:
# Show minutes.
time_offset = '%dm' % (t / 60)
elif segment_time >= 1:
# Show seconds.
time_offset = '%ds' % t
else:
# Show fractions.
time_offset = '%.2fs' % t
divs.append({
'store_len': store_len,
'load_len': load_len,
'trans_len': max(segment_height - store_len - load_len, 0),
'store_count': div['stores'],
'load_count': div['loads'],
'start': div['start'],
'end': div['end'],
'time_offset': time_offset,
})
if analysis:
start_time = DateTime(divs[0]['start']).aCommonZ()
end_time = DateTime(divs[-1]['end']).aCommonZ()
else:
start_time = ''
end_time = ''
res = {'start_time': start_time,
'end_time': end_time,
'divs': divs,
'total_store_count': total_store_count,
'total_load_count': total_load_count,
}
return res
Globals.default__class_init__(CacheManager)
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<h3>Recent Database Activity</h3>
<dtml-with expr="getActivityChartData(200, REQUEST)" mapping>
<table>
<tr>
<th valign="top">Keep History (seconds)</th>
<td>
<form method="POST" action="&dtml-URL1;/manage_setHistoryLength">
<input type="text" name="length" value="&dtml-getHistoryLength;" />
<input type="submit" name="submit" value="Save changes" />
</form>
</td>
</tr>
<tr>
<th valign="top">Displayed Range</th>
<td>&dtml-start_time; to<br />
&dtml-end_time;</td>
</tr>
<tr>
<th></th>
<td>
<form method="GET" action="&dtml-URL;">
<input type="submit" name="submit" value="Show current chart" />
</form>
</td>
</tr>
</table>
<p></p>
<div align="center">
<table style="border: solid thin black;">
<tr>
<td></td>
<dtml-in divs mapping>
<dtml-let url="REQUEST['URL'] + ('?chart_start=%s&chart_end=%s'
% (start, end))">
<td height="200" width="32"><a href="&dtml-url;"><dtml-if
trans_len><img src="transparent_bar" width="32"
height="&dtml-trans_len;" border="0" /><br /></dtml-if><dtml-if
store_len><img src="store_bar" width="32"
height="&dtml-store_len;" border="0" /><br /></dtml-if><dtml-if
load_len><img src="load_bar" width="32"
height="&dtml-load_len;" border="0" /></dtml-if></a></td>
</dtml-let>
</dtml-in>
</tr>
<tr>
<th align="left"><font color="#ff0000">Object stores</font></th>
<dtml-in divs mapping>
<td align="right"><dtml-let url="REQUEST['URL'] +
('?chart_start=%s&chart_end=%s'
% (start, end))"><a href="&dtml-url;"><font
color="#ff0000">&dtml-store_count;</font></a></dtml-let></td>
</dtml-in>
<th align="left">&nbsp; Total:
<font color="#ff0000">&dtml-total_store_count;</font>
</th>
</tr>
<tr>
<th align="left" valign="top"><font color="#000080">Object loads</font></th>
<dtml-in divs mapping>
<td align="right"><dtml-let url="REQUEST['URL'] +
('?chart_start=%s&chart_end=%s'
% (start, end))"><a href="&dtml-url;"><font
color="#000080">&dtml-load_count;</font></a></dtml-let><br />
<font size="-2">&dtml-time_offset;</font></td>
</dtml-in>
<th align="left" valign="top">&nbsp; Total:
<font color="#000080">&dtml-total_load_count;</font>
</th>
</tr>
</table>
</div>
</dtml-with>
<dtml-var manage_page_footer>
......@@ -105,7 +105,7 @@ class HelpSys(Acquisition.Implicit, ObjectManager, Item, Persistent):
script='window.open(\'%s\',\'zope_help\',\'width=600,' \
'height=500,menubar=yes,toolbar=yes,scrollbars=yes,' \
'resizable=yes\').focus(); return false;' % help_url
'resizable=yes\'); return false;' % help_url
h_link='<a href="%s" onClick="%s" onMouseOver="window.status=' \
'\'Open online help\'; return true;" onMouseOut="' \
......
Database Management - Activity
Description
This view displays activity in the ZODB over a period of time.
It shows how many objects were loaded and stored. You can use
this information to determine the optimal memory cache size for
your Zope application. You can also use it to discover
applications that write to the database too often.
Information
'Keep History' -- Lets you define how many seconds of history
to keep for analysis. 3600 is one hour. 86400 is one day.
Note that in the current implementation, analysis data is
kept only in memory and is never stored to disk, so each time
you restart, you lose the historical information.
'Displayed Range' -- Tells you what period of time is displayed
by the chart.
'Show current chart' -- Redisplays the chart for the current
time.
The chart contains a bar graph. The rightmost bar shows the
most recent activity. The red portion indicates the number of
objects stored and the blue portion indicates the number of
objects loaded during that time period. To the right of the
graph there is a total.
If you click on a bar, the chart will zoom in on the time
period for just that bar. You will see the details of the
activity during that short time period. Click the "Show current
chart" button to return to the chart for the current time.
How to use this information
Once Zope has loaded enough objects, the ZODB cache consistently
keeps in the cache the number of objects you specify under the
"Cache Parameters" tab. Because the cache size is so consistent
and ZODB is so transparent to both the user and
application developer, Zope applications can invisibly develop a
performance problem by loading objects from ZODB on every request.
Also, if the cache size is set too high, Zope will consume more
RAM than it needs. You need to find a good balance that fits
your site. If the bar chart shows a large number of objects being
loaded all the time, increase the cache size, which will increase
memory usage but should also increase performance. If the
chart shows little activity even though the site is visited
frequently, you can reduce the cache size so Zope will consume less
RAM.
As your site changes, its cache size requirements may change also,
so remember to make adjustments over time.
If the graph shows a lot of writes (a significant portion of red),
some application or product may be writing to the database too
frequently. Check the "undo" log for clues. Note that the activity
graph does not show activity in mounted databases, so objects loaded
and stored by the sessioning machinery are not counted in the graph.
......@@ -47,6 +47,10 @@ else:
Globals.BobobaseName = DB.getName()
sys.modules['Zope.custom_zodb']=m
if DB.getActivityMonitor() is None:
from ZODB.ActivityMonitor import ActivityMonitor
DB.setActivityMonitor(ActivityMonitor())
Globals.DB=DB # Ick, this is temporary until we come up with some registry
# Hook for providing multiple transaction object manager undo support:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment