<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>ControlSystemWorks Blog - alarming</title>
    <link>http://www.controlsystemworks.com/blog/</link>
    <description>Of CSWorks and software development</description>
    <language>en-us</language>
    <copyright>ControlSystemWorks.com</copyright>
    <lastBuildDate>Tue, 16 Mar 2010 06:13:25 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>support@ControlSystemWorks.net</managingEditor>
    <webMaster>support@ControlSystemWorks.net</webMaster>
    <item>
      <trackback:ping>http://www.controlsystemworks.com/blog/Trackback.aspx?guid=d337da96-7a38-4bd9-be01-af47215d943b</trackback:ping>
      <pingback:server>http://www.controlsystemworks.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.controlsystemworks.com/blog/PermaLink,guid,d337da96-7a38-4bd9-be01-af47215d943b.aspx</pingback:target>
      <dc:creator>Sergey Sorokin</dc:creator>
      <wfw:comment>http://www.controlsystemworks.com/blog/CommentView,guid,d337da96-7a38-4bd9-be01-af47215d943b.aspx</wfw:comment>
      <wfw:commentRss>http://www.controlsystemworks.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d337da96-7a38-4bd9-be01-af47215d943b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font color="#000000" face="Verdana">I am always curious about my system performance.
In this lab I will give CSWorks Alarming subsystem a hard time and see how it can
handle it.<br /><br /><b>Environment</b><br /><br />
CSWorks 1.1.3700.0<br />
Server: Intel Core 2 Quad Q6600 @ 2.40GHz, 3.25 GB RAM, Windows XP SP3<br />
Client: Intel Core 2 Duo T5300 @ 1.73GHz (notebook), 2 GB RAM, Windows XP SP3<br />
Network: Wireless 54 Mbps<br /><br /><b>Set-up</b><br /><br />
1. Install SQL Server 2008 Express on your server machine.<br /><br />
2. Create database "CSWorks"<br /><br />
3. Create AlarmEvents table - see "createCommand" parameter of &lt;dbTarget name="Standard
SQLServer DbTarget".../&gt; in CSWorks.Server.AlarmService.exe.config.<br /><br />
4. Configure SQL Server data source in CSWorks.Server.AlarmService.exe.config:<br /><br /><font size="1" color="#0000ff">&lt;dbTargets activeDbTarget=<b>"Standard SQLServer
DbTarget"</b>&gt;<br />
  &lt;dbTarget name="Standard SQLServer DbTarget"  ...  <b>connectionString="Data
Source=myserverbox\SQLEXPRESS; Initial Catalog=CSWorks;user id=sa;password=youknowit"</b> ...  <b>maxEventAge="3600"</b> .../&gt;</font><br /><br />
Please note we tell CSWorks Alarm Service to keep alarm event records in the database
for an hour so we can accumulate some amount of load data.<br /><br />
5. Restart CSWorks Alarm Service. Make sure events are now written to CSWorks database
(run "select * from AlarmEvents" to confirm it).<br /><br />
6. Configure Silverlight web services URL for Alarm Demo application, so it can run
from remote machine - make sure that ServiceReferences.ClientConfig in<br /><br />
C:\Program Files\CSWorks\Demo\Web\ClientBin\CSWorks.Client.AlarmDemo.xap<br /><br />
says 
<br /><br /><font size="1" color="#0000ff">&lt;endpoint address="http://<b>myserverbox</b>/CSWorksDemo/AlarmWebService/Service.asmx"
...&gt;</font><br /><br />
If you need more details, <a href="http://www.controlsystemworks.com/blog/2010/02/25/RunningCSWorksDemoApplicationsFromRemoteClients.aspx">see
this post</a>.<br /><br />
7. Run Alarm Demo from from remote client and make sure it works properly.<br /><br />
8. Create a script that generates 3000 alarm descriptions in 10 alarm groups (<a href="content/binary/2010-03-16-GenAlarms.txt">download
it here</a>),  run "cscript genalarms.js &gt; alarms.txt", copy generated alarm
groups to Alarms.xml, <font color="#0000ff">alarmGroups</font> element. Here is an
excerpt:<br /><br /><font size="1" color="#0000ff">&lt;alarmGroup id='00000000-AAAA-0000-0000-000000000000'
description='Alarm group #0000'&gt;<br />
  &lt;alarms&gt;<br />
    &lt;alarm id='{00000000-0000-0000-0000-000000000000}' description='Total
intake tank load, id 00000000' expression='tank1 + tank2 + tank3 + tank4' saveHistory='true'
... &gt;<br />
      &lt;thresholds&gt;<br />
        &lt;threshold ... message='Total intake
tank load too high: {0:#,##0.00}, exceeds {1:#,##0.00}, id 00000000' ... /&gt;<br /><br />
        ...<br /><br />
    &lt;alarm id='{00000000-0000-0000-0000-000000090299}' description='Total
intake tank load, id 00090299' expression='tank1 + tank2 + tank3 + tank4' saveHistory='true'
... &gt;<br />
      &lt;thresholds&gt;<br />
        &lt;threshold ... message='Total intake
tank load too high: {0:#,##0.00}, exceeds {1:#,##0.00}, id 00090299' ... /&gt;</font></font>
        </p>
        <p>
          <font color="#000000" face="Verdana">
            <font size="1" color="#0000ff">     
  ...<br /></font>
          </font>
        </p>
        <p>
          <font color="#000000" face="Verdana">
            <font size="1" color="#0000ff">     
&lt;/thresholds&gt;<br />
    &lt;/alarm&gt;<br />
  &lt;/alarms&gt;<br />
&lt;/alarmGroup&gt;<br /></font>
          </font>
        </p>
        <p>
          <font color="#000000" face="Verdana">Give CSWorks Alarm Service a couple of seconds
to digest the changes (this piece doesn't scale of course, so only one server CPU
is involved).</font>
        </p>
        <p>
          <font color="#000000" face="Verdana">9. Add newly created alarm group ids to AlarmWebService
web.config file:</font>
        </p>
        <p>
          <font size="1" color="#0000ff" face="Verdana">&lt;alarmGroups&gt;<br />
  ...<br />
  &lt;alarmGroup alarmGroupId='</font>
          <font size="1" color="#0000ff" face="Verdana">00000000-AAAA-0000-0000-000000000000'
description='Alarm group #0000'</font>
          <font size="1" color="#0000ff" face="Verdana">/&gt;<br />
  ...<br />
&lt;/alarmGroups&gt;</font>
        </p>
        <p>
          <font color="#000000" face="Verdana">10. Subscribe to newly created alarm groups in
Alarm Demo application, either using "Subscribe..." menu command, or in XAML:</font>
        </p>
        <p>
          <font size="1" color="#0000ff" face="Verdana">&lt;alarm:AlarmSummary ... AlarmGroupIds="...;</font>
          <font color="#000000" face="Verdana">
            <font size="1" color="#0000ff">00000000-AAAA-0000-0000-000000000000;..."
/&gt;<br /></font>
          </font>
        </p>
        <p>
          <font color="#000000" face="Verdana">11. After starting Alarm Demo on your client
machine you will have 12000 new alarm events and considerable spikes in network usage:<br /><br /><img src="content/binary/2010-03-16-3kAlarmSummary.png" /><br /><br /><b>Let It Brew</b><br /><br />
Go grab a coffee and have a chat with your colleagues while CSWorks Alarm Service
generates some alarm events.<br /><br /><b>Analyze This</b><br /><br />
Let's look at the alarm activity: System Monitor -&gt; CSWorksAlarmService performance
object -&gt; Alarm Events per second:<br /><br /><img src="content/binary/2010-03-16-PerfCounter.png" /><br /><br />
~730 alarm events per second on average with spikes up to 9000 events per second.
This correlates with our setup, remember: an alarm becoming inactive is an event too,
and we have 4 thresholds per alarm. So, <b>each spike is basically a burst of 3000*6=18000
events generated in 5 seconds</b>. Now let's look at the CPU usage on the server box:<br /><br /><img src="content/binary/2010-03-16-ServerCpuUsage.png" /><br /><br />
- not bad, the load is distributed properly. Let's make sure that all those events
actually ended up in the database:<br /><br /><img src="content/binary/2010-03-16-DatabaseRecords.png" /><br /><br />
- good, those 700 000 events definitely did. Now back to the client.<br /><br />
With filtering turned off, the client seems to handle the spikes pretty well: Alarm
Summary items are updated with 1-3 seconds delays. Things are getting worse if you
apply a filter (say, show only active alarms): delay bumps up to 15 seconds. And of
course, one of the processors on the client box is overloaded by filtering and data
presentation activities. And it's not easy to scale them out: Silverlight dispatcher
is single-threaded. Ok, there is some space for improvement on the client side.<br /><br />
And a word about network traffic for the inquiring minds. Fiddler tool tells all the
truth and it ain't that ugly:<br /><br /><img src="content/binary/2010-03-16-Fiddler.png" /><br /><br />
- each 2.3 MB per spike translates into ~130 bytes per event. Keep in mind that
every event carries a unique text message. Not bad.<br /><br /><b>Back to Normal</b><br /><br />
Restore Alarms.xml - you have made a copy of the original file before inserting 3000
alarm descriptions, didn't you?  Again, let CSWorks Alarm Service digest the
changes and in a couple of seconds, alarm summary is almost clear, showing only a
couple of events. The storm is over.<br /><br /><b>Summary</b><br /><br />
Server load is scaled properly, stable and predictable. Network traffic is predictable
too, those tuning freaks out there can gain some bandwidth using HTTP compression
(yes, Silverlight supports it). Database performance doesn't seem to be an issue at
all. The only bottleneck in this scenario is client CPU consumption when processing
bursts of 18000 events. So, the recommendation is: if your operator needs to keep
an eye on 18000 events fired in five seconds, buy him/her a better client box. </font>
        </p>
        <img width="0" height="0" src="http://www.controlsystemworks.com/blog/aggbug.ashx?id=d337da96-7a38-4bd9-be01-af47215d943b" />
      </body>
      <title>CSWorks Alarming Performance - Lab 01</title>
      <guid isPermaLink="false">http://www.controlsystemworks.com/blog/PermaLink,guid,d337da96-7a38-4bd9-be01-af47215d943b.aspx</guid>
      <link>http://www.controlsystemworks.com/blog/2010/03/16/CSWorksAlarmingPerformanceLab01.aspx</link>
      <pubDate>Tue, 16 Mar 2010 06:13:25 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;I am always curious about my system performance.
In this lab I will give CSWorks Alarming subsystem a hard time and see how it can
handle it.&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Environment&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;
CSWorks 1.1.3700.0&lt;br&gt;
Server: Intel Core 2 Quad Q6600 @ 2.40GHz, 3.25 GB RAM, Windows XP SP3&lt;br&gt;
Client: Intel Core 2 Duo T5300 @ 1.73GHz (notebook), 2 GB RAM, Windows XP SP3&lt;br&gt;
Network: Wireless 54 Mbps&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Set-up&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;
1. Install SQL Server 2008 Express on your server machine.&lt;br&gt;
&lt;br&gt;
2. Create database "CSWorks"&lt;br&gt;
&lt;br&gt;
3. Create AlarmEvents table - see "createCommand" parameter of &amp;lt;dbTarget name="Standard
SQLServer DbTarget".../&amp;gt; in CSWorks.Server.AlarmService.exe.config.&lt;br&gt;
&lt;br&gt;
4. Configure SQL Server data source in CSWorks.Server.AlarmService.exe.config:&lt;br&gt;
&lt;br&gt;
&lt;font size="1" color="#0000ff"&gt;&amp;lt;dbTargets activeDbTarget=&lt;b&gt;"Standard SQLServer
DbTarget"&lt;/b&gt;&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;dbTarget name="Standard SQLServer DbTarget"&amp;nbsp; ...&amp;nbsp; &lt;b&gt;connectionString="Data
Source=myserverbox\SQLEXPRESS; Initial Catalog=CSWorks;user id=sa;password=youknowit"&lt;/b&gt; ...&amp;nbsp; &lt;b&gt;maxEventAge="3600"&lt;/b&gt; .../&amp;gt;&lt;/font&gt;
&lt;br&gt;
&lt;br&gt;
Please note we tell CSWorks Alarm Service to keep alarm event records in the database
for an hour so we can accumulate some amount of load data.&lt;br&gt;
&lt;br&gt;
5. Restart CSWorks Alarm Service. Make sure events are now written to CSWorks database
(run "select * from AlarmEvents" to confirm it).&lt;br&gt;
&lt;br&gt;
6. Configure Silverlight web services URL for Alarm Demo application, so it can run
from remote machine - make sure that ServiceReferences.ClientConfig in&lt;br&gt;
&lt;br&gt;
C:\Program Files\CSWorks\Demo\Web\ClientBin\CSWorks.Client.AlarmDemo.xap&lt;br&gt;
&lt;br&gt;
says 
&lt;br&gt;
&lt;br&gt;
&lt;font size="1" color="#0000ff"&gt;&amp;lt;endpoint address="http://&lt;b&gt;myserverbox&lt;/b&gt;/CSWorksDemo/AlarmWebService/Service.asmx"
...&amp;gt;&lt;/font&gt;
&lt;br&gt;
&lt;br&gt;
If you need more details, &lt;a href="http://www.controlsystemworks.com/blog/2010/02/25/RunningCSWorksDemoApplicationsFromRemoteClients.aspx"&gt;see
this post&lt;/a&gt;.&lt;br&gt;
&lt;br&gt;
7. Run Alarm Demo from from remote client and make sure it works properly.&lt;br&gt;
&lt;br&gt;
8. Create a script that generates 3000 alarm descriptions in 10 alarm groups (&lt;a href="content/binary/2010-03-16-GenAlarms.txt"&gt;download
it here&lt;/a&gt;),&amp;nbsp; run "cscript genalarms.js &amp;gt; alarms.txt", copy generated alarm
groups to Alarms.xml, &lt;font color="#0000ff"&gt;alarmGroups&lt;/font&gt; element. Here is an
excerpt:&lt;br&gt;
&lt;br&gt;
&lt;font size="1" color="#0000ff"&gt;&amp;lt;alarmGroup id='00000000-AAAA-0000-0000-000000000000'
description='Alarm group #0000'&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;alarms&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;alarm id='{00000000-0000-0000-0000-000000000000}' description='Total
intake tank load, id 00000000' expression='tank1 + tank2 + tank3 + tank4' saveHistory='true'
... &amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;thresholds&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;threshold ... message='Total intake
tank load too high: {0:#,##0.00}, exceeds {1:#,##0.00}, id 00000000' ... /&amp;gt;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;alarm id='{00000000-0000-0000-0000-000000090299}' description='Total
intake tank load, id 00090299' expression='tank1 + tank2 + tank3 + tank4' saveHistory='true'
... &amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;thresholds&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;threshold ... message='Total intake
tank load too high: {0:#,##0.00}, exceeds {1:#,##0.00}, id 00090299' ... /&amp;gt;&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;&lt;font size="1" color="#0000ff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp; ...&lt;br&gt;
&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;&lt;font size="1" color="#0000ff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;lt;/thresholds&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/alarm&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;/alarms&amp;gt;&lt;br&gt;
&amp;lt;/alarmGroup&amp;gt;&lt;br&gt;
&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;Give CSWorks Alarm Service a couple of seconds
to digest the changes (this piece doesn't scale of course, so only one server CPU
is involved).&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;9. Add newly created alarm group ids to AlarmWebService
web.config file:&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size="1" color="#0000ff" face="Verdana"&gt;&amp;lt;alarmGroups&amp;gt;&lt;br&gt;
&amp;nbsp; ...&lt;br&gt;
&amp;nbsp; &amp;lt;alarmGroup alarmGroupId='&lt;/font&gt;&lt;font size="1" color="#0000ff" face="Verdana"&gt;00000000-AAAA-0000-0000-000000000000'
description='Alarm group #0000'&lt;/font&gt;&lt;font size="1" color="#0000ff" face="Verdana"&gt;/&amp;gt;&lt;br&gt;
&amp;nbsp; ...&lt;br&gt;
&amp;lt;/alarmGroups&amp;gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;10. Subscribe to newly created alarm groups in
Alarm Demo application, either using "Subscribe..." menu command, or in XAML:&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size="1" color="#0000ff" face="Verdana"&gt;&amp;lt;alarm:AlarmSummary ... AlarmGroupIds="...;&lt;/font&gt;&lt;font color="#000000" face="Verdana"&gt;&lt;font size="1" color="#0000ff"&gt;00000000-AAAA-0000-0000-000000000000;..."
/&amp;gt;&lt;br&gt;
&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#000000" face="Verdana"&gt;11. After starting Alarm Demo on your client
machine you will have 12000 new alarm events and considerable spikes in network usage:&lt;br&gt;
&lt;br&gt;
&lt;img src="content/binary/2010-03-16-3kAlarmSummary.png"&gt;
&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Let It Brew&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;
Go grab a coffee and have a chat with your colleagues while CSWorks Alarm Service
generates some alarm events.&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Analyze This&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;
Let's look at the alarm activity: System Monitor -&amp;gt; CSWorksAlarmService performance
object -&amp;gt; Alarm Events per second:&lt;br&gt;
&lt;br&gt;
&lt;img src="content/binary/2010-03-16-PerfCounter.png"&gt;
&lt;br&gt;
&lt;br&gt;
~730 alarm events per second on average with spikes up to 9000 events per second.
This correlates with our setup, remember: an alarm becoming inactive is an event too,
and we have 4 thresholds per alarm. So, &lt;b&gt;each spike is basically a burst of 3000*6=18000
events generated in 5 seconds&lt;/b&gt;. Now let's look at the CPU usage on the server box:&lt;br&gt;
&lt;br&gt;
&lt;img src="content/binary/2010-03-16-ServerCpuUsage.png"&gt;
&lt;br&gt;
&lt;br&gt;
- not bad, the load is distributed properly. Let's make sure that all those events
actually ended up in the database:&lt;br&gt;
&lt;br&gt;
&lt;img src="content/binary/2010-03-16-DatabaseRecords.png"&gt;
&lt;br&gt;
&lt;br&gt;
- good, those 700 000 events definitely did. Now back to the client.&lt;br&gt;
&lt;br&gt;
With filtering turned off, the client seems to handle the spikes pretty well: Alarm
Summary items are updated with 1-3 seconds delays. Things are getting worse if you
apply a filter (say, show only active alarms): delay bumps up to 15 seconds. And of
course, one of the processors on the client box is overloaded by filtering and data
presentation activities. And it's not easy to scale them out: Silverlight dispatcher
is single-threaded. Ok, there is some space for improvement on the client side.&lt;br&gt;
&lt;br&gt;
And a word about network traffic for the inquiring minds. Fiddler tool tells all the
truth and it ain't that ugly:&lt;br&gt;
&lt;br&gt;
&lt;img src="content/binary/2010-03-16-Fiddler.png"&gt;
&lt;br&gt;
&lt;br&gt;
- each 2.3 MB per spike&amp;nbsp;translates into ~130 bytes per event. Keep in mind that
every event carries a unique text message. Not bad.&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Back to Normal&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;
Restore Alarms.xml - you have made a copy of the original file before inserting 3000
alarm descriptions, didn't you?&amp;nbsp; Again, let CSWorks Alarm Service digest the
changes and in a couple of seconds, alarm summary is almost clear, showing only a
couple of events. The storm is over.&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Summary&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;
Server load is scaled properly, stable and predictable. Network traffic is predictable
too, those tuning freaks out there can gain some bandwidth using HTTP compression
(yes, Silverlight supports it). Database performance doesn't seem to be an issue at
all. The only bottleneck in this scenario is client CPU consumption when processing
bursts of 18000 events. So, the recommendation is: if your operator needs to keep
an eye on 18000 events fired in five seconds, buy him/her a better client box.&amp;nbsp;&lt;/font&gt; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.controlsystemworks.com/blog/aggbug.ashx?id=d337da96-7a38-4bd9-be01-af47215d943b" /&gt;</description>
      <comments>http://www.controlsystemworks.com/blog/CommentView,guid,d337da96-7a38-4bd9-be01-af47215d943b.aspx</comments>
      <category>alarming</category>
      <category>performance</category>
    </item>
  </channel>
</rss>