<?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 - performance</title>
    <link>http://www.controlsystemworks.com/blog/</link>
    <description>Of CSWorks and software development</description>
    <language>en-us</language>
    <copyright>ControlSystemWorks.com</copyright>
    <lastBuildDate>Wed, 19 May 2010 21:18:06 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=0d6a6133-fc63-4893-992e-46336e15c8ad</trackback:ping>
      <pingback:server>http://www.controlsystemworks.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.controlsystemworks.com/blog/PermaLink,guid,0d6a6133-fc63-4893-992e-46336e15c8ad.aspx</pingback:target>
      <dc:creator>Sergey Sorokin</dc:creator>
      <wfw:comment>http://www.controlsystemworks.com/blog/CommentView,guid,0d6a6133-fc63-4893-992e-46336e15c8ad.aspx</wfw:comment>
      <wfw:commentRss>http://www.controlsystemworks.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=0d6a6133-fc63-4893-992e-46336e15c8ad</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If you are curious about the number of Trend controls you can run against your CSWorks
server infrastructure, you may find this post interesting. We will make minor changes
to historical data server configuration, run a few Trend control clients against it
and analyze what we see. 
</p>
        <p>
          <font size="4">Environment </font>
        </p>
        <p>
CSWorks 1.2.3800.0<br />
Server: Intel Core 2 Duo @ 2.40GHz, 2 GB RAM, Windows Server 2008<br />
Client: Intel Core 2 Duo T5300 @ 1.73GHz (notebook), 2 GB RAM, Windows XP SP3<br />
Network: Wireless 54 Mbps 
</p>
        <p>
          <font size="4">Server Configuration </font>
        </p>
        <p>
1. As usual, we have to configure History Recorder so it uses some scalable database.
Install SQL Server 2008 Express on your server machine. 
<br /><br />
2. Create database "CSWorks" 
<br /><br />
3. Create HistoricalData table - see "createCommand" parameter of &lt;dbtarget ...=""
name="Standard SQLServer DbTarget"&gt; in CSWorks.Server.HistoryRecorderService.exe.config. 
<br /><br />
4. Configure SQL Server data source and make it active in CSWorks.Server.HistoryRecorderService.exe.config:
</p>
        <font size="1" color="#0000ff" face="Verdana">
          <font color="#0000ff">&lt;dbTargetConfig&gt;<br />
  &lt;dbTargets <strong><font color="#ff0000">activeDbTarget="Standard SQLServer
DbTarget</font>"</strong>&gt;<br />
    &lt;dbTarget name="Standard SQLite DbTarget" ...<br />
      ...<br />
    /&gt;<br />
    &lt;dbTarget name="Standard SQLServer DbTarget"<br />
      providerInvariantName="System.Data.SqlClient"<br />
      connectionString="<font color="#ff0000">Data Source=localhost\sqlexpress;
Initial Catalog=CSWorks;user id=sa;password=...</font>;"<br />
      ...<br />
    /&gt;<br />
  &lt;/dbTargets&gt;<br />
&lt;/dbTargetConfig&gt;</font>
        </font>
        <br />
        <br />
5. Configure HistoryReaderWebService to read historical data from this database. In
the web.config, assign SQLServer target to the primary partition and specify correct
connection string:<br /><br /><font size="1" color="#0000ff">  &lt;historyTopology&gt;<br />
    &lt;historyPartitions&gt;<br />
      &lt;historyPartition name="partition1" primaryDbTarget="<b><font color="#ff0000">partition1
Primary DbTarget (SQLServer)</font></b>" secondaryDbTarget=""&gt;<br />
        ..<br />
      &lt;/historyPartition&gt;<br />
    &lt;/historyPartitions&gt;<br />
  &lt;/historyTopology&gt;<br /><br />
  &lt;dbTargetConfig&gt;<br />
    &lt;dbTargets&gt;<br />
      ...<br />
      &lt;dbTarget name="partition1 Primary DbTarget (SQLServer)"<br />
               
providerInvariantName="System.Data.SqlClient"<br />
               
connectionString="<font color="#ff0000">Data Source=localhost\sqlexpress; Initial
Catalog=CSWorks;user id=sa;password=...;</font>"<br />
               
...<br />
               
/&gt;<br />
    &lt;/dbTargets&gt;<br />
  &lt;/dbTargetConfig&gt;<br /></font><br />
6. Restart HistoryRecorder service and verify that it writes observation to the newly
configured database. 
<p><font size="4">Running clients </font></p><p>
Before running the clients, make sure you have prepared *.clientConfig in CSWorks.Client.TrendDemo.xap
to run from a remote machine. Please see <a target="_blank" href="http://www.controlsystemworks.com/blog/2010/02/25/RunningCSWorksDemoApplicationsFromRemoteClients.aspx">this
post</a> for details. 
<br /><br />
Now run a few Trend clients on your client machine using this command:<br /><br /><font size="1" color="#0000ff">start iexplore "http://myserver/CSWorksDemo/TrendDemo.html"</font><br /><br />
I ran 25 instances, increasing the load by 5-instance chunks. 
</p><p><font size="4">Results </font></p><p>
All 25 clients run without problems, trending data (both live and historical) arrives
without delays, server seems to be perfoming fine. <a target="_blank" href="content/binary/2010-05-19-ServerPerformance.png">Here
is a screenshot</a> made on the server machine. Clients consume about 200K of live
and historical data every second, server machine uses about 35% of its CPU capacity.
SQL Server and ASP.NET worker process are working hard (14% and 18%, respectively)
to deliver historical data to the clients. 
<br /><br />
The spikes in data transfer rates mark moments when Trend control were re-querying
bigger amounts of historical data - View-&gt;Tracking setting were set to On for all
Trend control instances, and all instances were refreshing the whole picture synchronously
(well, in chunks of 5 instances, of course). 
<br /><br />
The spikes in CPU consumption mark moments when I ran chunks of 5 IE instances. 
</p><p><font size="4">Summary </font></p><p>
Not bad for a commodity server box that runs every piece of the deployment: all CSWorks
services (LiveData, Alarm, HistoryRecorder), web services and database engine. Potential
bottlenecks are:<br />
- the database - not surprising;<br />
- web service layer - but we can scale it out using web farm. 
</p><img width="0" height="0" src="http://www.controlsystemworks.com/blog/aggbug.ashx?id=0d6a6133-fc63-4893-992e-46336e15c8ad" /></body>
      <title>Trending client performance - Lab 03</title>
      <guid isPermaLink="false">http://www.controlsystemworks.com/blog/PermaLink,guid,0d6a6133-fc63-4893-992e-46336e15c8ad.aspx</guid>
      <link>http://www.controlsystemworks.com/blog/2010/05/19/TrendingClientPerformanceLab03.aspx</link>
      <pubDate>Wed, 19 May 2010 21:18:06 GMT</pubDate>
      <description>&lt;p&gt;
If you are curious about the number of Trend controls you can run against your CSWorks
server infrastructure, you may find this post interesting. We will make minor changes
to historical data server configuration, run a few Trend control clients against it
and analyze what we see. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Environment &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
CSWorks 1.2.3800.0&lt;br&gt;
Server: Intel Core 2 Duo @ 2.40GHz, 2 GB RAM, Windows Server 2008&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;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Server Configuration &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
1. As usual, we have to configure History Recorder so it uses some scalable database.
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 HistoricalData table - see "createCommand" parameter of &amp;lt;dbtarget ...=""
name="Standard SQLServer DbTarget"&amp;gt; in CSWorks.Server.HistoryRecorderService.exe.config. 
&lt;br&gt;
&lt;br&gt;
4. Configure SQL Server data source and make it active in CSWorks.Server.HistoryRecorderService.exe.config:
&lt;/p&gt;
&lt;font size="1" color="#0000ff" face="Verdana"&gt;&lt;font color="#0000ff"&gt;&amp;lt;dbTargetConfig&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;dbTargets &lt;strong&gt;&lt;font color="#ff0000"&gt;activeDbTarget="Standard SQLServer
DbTarget&lt;/font&gt;"&lt;/strong&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dbTarget name="Standard SQLite DbTarget" ...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dbTarget name="Standard SQLServer DbTarget"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;providerInvariantName="System.Data.SqlClient"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;connectionString="&lt;font color="#ff0000"&gt;Data Source=localhost\sqlexpress;
Initial Catalog=CSWorks;user id=sa;password=...&lt;/font&gt;;"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; /&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/dbTargets&amp;gt;&lt;br&gt;
&amp;lt;/dbTargetConfig&amp;gt;&lt;/font&gt;&lt;/font&gt;
&lt;br&gt;
&lt;br&gt;
5. Configure HistoryReaderWebService to read historical data from this database. In
the web.config, assign SQLServer target to the primary partition and specify correct
connection string:&lt;br&gt;
&lt;br&gt;
&lt;font size="1" color="#0000ff"&gt;&amp;nbsp; &amp;lt;historyTopology&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;historyPartitions&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;historyPartition name="partition1" primaryDbTarget="&lt;b&gt;&lt;font color="#ff0000"&gt;partition1
Primary DbTarget (SQLServer)&lt;/font&gt;&lt;/b&gt;" secondaryDbTarget=""&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ..&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/historyPartition&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/historyPartitions&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;/historyTopology&amp;gt;&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;lt;dbTargetConfig&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dbTargets&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dbTarget name="partition1 Primary DbTarget (SQLServer)"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
providerInvariantName="System.Data.SqlClient"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
connectionString="&lt;font color="#ff0000"&gt;Data Source=localhost\sqlexpress; Initial
Catalog=CSWorks;user id=sa;password=...;&lt;/font&gt;"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/dbTargets&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;/dbTargetConfig&amp;gt;&lt;br&gt;
&lt;/font&gt; 
&lt;br&gt;
6. Restart HistoryRecorder service and verify that it writes observation to the newly
configured database. 
&lt;p&gt;
&lt;font size="4"&gt;Running clients &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Before running the clients, make sure you have prepared *.clientConfig in CSWorks.Client.TrendDemo.xap
to run from a remote machine. Please see &lt;a target="_blank" href="http://www.controlsystemworks.com/blog/2010/02/25/RunningCSWorksDemoApplicationsFromRemoteClients.aspx"&gt;this
post&lt;/a&gt; for details. 
&lt;br&gt;
&lt;br&gt;
Now run a few Trend clients on your client machine using this command:&lt;br&gt;
&lt;br&gt;
&lt;font size="1" color="#0000ff"&gt;start iexplore "http://myserver/CSWorksDemo/TrendDemo.html"&lt;/font&gt;
&lt;br&gt;
&lt;br&gt;
I ran 25 instances, increasing the load by 5-instance chunks. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Results &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
All 25 clients run without problems, trending data (both live and historical) arrives
without delays, server seems to be perfoming fine. &lt;a target="_blank" href="content/binary/2010-05-19-ServerPerformance.png"&gt;Here
is a screenshot&lt;/a&gt; made on the server machine. Clients consume about 200K of live
and historical data every second, server machine uses about 35% of its CPU capacity.
SQL Server and ASP.NET worker process are working hard (14% and 18%, respectively)
to deliver historical data to the clients. 
&lt;br&gt;
&lt;br&gt;
The spikes in data transfer rates mark moments when Trend control were re-querying
bigger amounts of historical data - View-&amp;gt;Tracking setting were set to On for all
Trend control instances, and all instances were refreshing the whole picture synchronously
(well, in chunks of 5 instances, of course). 
&lt;br&gt;
&lt;br&gt;
The spikes in CPU consumption mark moments when I ran chunks of 5 IE instances. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Summary &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Not bad for a commodity server box that runs every piece of the deployment: all CSWorks
services (LiveData, Alarm, HistoryRecorder), web services and database engine. Potential
bottlenecks are:&lt;br&gt;
- the database - not surprising;&lt;br&gt;
- web service layer - but we can scale it out using web farm. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.controlsystemworks.com/blog/aggbug.ashx?id=0d6a6133-fc63-4893-992e-46336e15c8ad" /&gt;</description>
      <comments>http://www.controlsystemworks.com/blog/CommentView,guid,0d6a6133-fc63-4893-992e-46336e15c8ad.aspx</comments>
      <category>historical data</category>
      <category>performance</category>
    </item>
    <item>
      <trackback:ping>http://www.controlsystemworks.com/blog/Trackback.aspx?guid=20a658ae-d7c3-4b0e-808f-59472db7098b</trackback:ping>
      <pingback:server>http://www.controlsystemworks.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.controlsystemworks.com/blog/PermaLink,guid,20a658ae-d7c3-4b0e-808f-59472db7098b.aspx</pingback:target>
      <dc:creator>Sergey Sorokin</dc:creator>
      <wfw:comment>http://www.controlsystemworks.com/blog/CommentView,guid,20a658ae-d7c3-4b0e-808f-59472db7098b.aspx</wfw:comment>
      <wfw:commentRss>http://www.controlsystemworks.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=20a658ae-d7c3-4b0e-808f-59472db7098b</wfw:commentRss>
      <title>History Recorder performance - Lab 02</title>
      <guid isPermaLink="false">http://www.controlsystemworks.com/blog/PermaLink,guid,20a658ae-d7c3-4b0e-808f-59472db7098b.aspx</guid>
      <link>http://www.controlsystemworks.com/blog/2010/04/20/HistoryRecorderPerformanceLab02.aspx</link>
      <pubDate>Tue, 20 Apr 2010 17:09:46 GMT</pubDate>
      <description>&lt;p&gt;
In the latest release of CSWorks, we have improved Historical Data Server performance.
Let's see what History Recorder is capable of now. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Environment &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
CSWorks 1.2.3730.0&lt;br&gt;
Server: Intel Core 2 Quad Q6600 @ 2.40GHz,&amp;nbsp;4 GB RAM, Windows&amp;nbsp;7&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Set-up&lt;/font&gt; 
&lt;/p&gt;
&lt;p&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 HistoricalData table - see "createCommand" parameter of 
&lt;dbtarget ...="" name="Standard SQLServer DbTarget"&gt;
in CSWorks.Server.HistoryRecorderService.exe.config. 
&lt;br&gt;
&lt;br&gt;
4. Configure SQL Server data source and make it active in CSWorks.Server.HistoryRecorderService.exe.config: 
&lt;/dbtarget&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size="1" color="#0000ff"&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;&amp;lt;dbTargetConfig&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;dbTargets &lt;strong&gt;&lt;font color="#ff0000"&gt;activeDbTarget="Standard SQLServer
DbTarget&lt;/font&gt;"&lt;/strong&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dbTarget name="Standard SQLite DbTarget" ...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dbTarget name="Standard SQLServer DbTarget"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;providerInvariantName="System.Data.SqlClient"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;connectionString="Data Source=localhost\sqlexpress;
Initial Catalog=CSWorks;user id=sa;password=...;"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;createCommand="..."&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeCommand="..."&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maintenanceCommand="delete top &lt;strong&gt;&lt;font color="#ff0000"&gt;(300000)&lt;/font&gt;&lt;/strong&gt; from
HistoricalData ..."&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxObservationAge=&lt;strong&gt;&lt;font color="#ff0000"&gt;"600"&lt;/font&gt;&lt;/strong&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeInterval="1"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maintenanceInterval=&lt;strong&gt;&lt;font color="#ff0000"&gt;"30"&lt;/font&gt;&lt;/strong&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxQueryLength="65535"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;queryDelimiter=";"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeTxnBeginCommand="..."&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeTxnCommitCommand="..."&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/dbTargets&amp;gt;&lt;br&gt;
&amp;lt;/dbTargetConfig&amp;gt;&lt;/font&gt;
&lt;br&gt;
&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Please note we tell History Recorder to keep alarm event records in the database for
10 minutes only, and we perform record cleaning every 30 seconds. This only because
our SQL Server is not capable of taking heavy load. 
&lt;br&gt;
&lt;br&gt;
5. Restart History Recorder service. Make sure events are now written to CSWorks database
(run "select * from HistoricalData" to confirm it). 
&lt;br&gt;
&lt;br&gt;
6. Using cscript tool, run a script that generates 2000 historical data points: 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="1" color="#0000ff" face="Courier New"&gt;function main()&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;var itemCount = 2000;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;WScript.Echo("RecorderDataPoints.xml");&lt;br&gt;
&amp;nbsp;&amp;nbsp;for (i = 0; i &amp;lt; itemCount; i++)&lt;br&gt;
&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var id = i.toString();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(id.length &amp;lt; 4)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id = "0" + id;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WScript.Echo("&lt;datapoint id="{00000000-0000-0000-0000-00000000&amp;quot; + id + &amp;quot;}" expression="tank1-&amp;quot; + id +&amp;quot;" description="Tank 1 fill - &amp;quot; + id + &amp;quot;"&gt;
");&lt;br&gt;
&amp;nbsp;&amp;nbsp;}&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
main();&lt;br&gt;
&lt;/datapoint&gt;
&lt;/font&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
7. Copy generated historical data point descriptions to RecorderDataPoints.xml: 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="1" color="#0000ff" face="Courier New"&gt;&amp;lt;dataPoints&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;dataPoint id='{00000000-0000-0000-0000-000000000000}' description='Tank
1 fill - 0000' expression='tank1-0000'/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;...&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;dataPoint id='{00000000-0000-0000-0000-000000001999}' description='Tank
1 fill - 1999' expression='tank1-1999'/&amp;gt;&lt;br&gt;
&amp;lt;/dataPoints&amp;gt;&lt;br&gt;
&lt;/font&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
History Recorder will pick up the change in a couple of seconds and will start saving
observation for those 2000 data points to the database. Give our setup some time to
stabilize. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Results&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
After 10 minutes, History Recorder maintains about 3.5 million observation records
in the database and writes about 6000 observation records every second on average.
Database file size is between 1 and 1.5 gigabytes. Here is a screenshot with Performance
Monitor and DbgView windows: 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="content/binary/2010-04-20-RecorderServicePerformance-big.gif" target="_blank"&gt;&lt;img src="content/binary/2010-04-20-RecorderServicePerformance.gif" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
Since our test live data changes in a very predictable way, there is a clear pattern
in observation recording on the top perfmon chart. History Recorder memory consumption
is under control too. Tracing shows that History Recorder deletes between 120000 and
270000 "obsolete" observations every 30 seconds. As you may have noticed, the maximum
number of record it is allowed to delete in one shot is 300K, see 'maintenanceCommand'
parameter above. Our setup is properly balanced, so History Recorder does not reach
this limit. 
&lt;/p&gt;
&lt;p&gt;
If you add more historical datapoints and make total count, say 5000, you may end
up in a situation when History Recorder simply cannot write all collected observations
in a timely manner, and they will accumulate in the memory buffer. Major symptom will
be growing memory consumption by History Recorder. CSWorks 1.2.3800.0 introduces "Write
Buffer Size" performance counter that shows current number observations to be written
to the database by HistoryRecorder, so this overload scenario becomes more obvious. 
&lt;/p&gt;
&lt;p&gt;
&lt;font size="4"&gt;Summary &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Please plan your historical data management carefully. Use scalable database engine,
and give it a lot of spare CPU resources. Use multiple History Recorder machines if
needed. If the amount of data is extremely big, use multiple databases and apply partitioning
technique described in CSWorks documentation. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.controlsystemworks.com/blog/aggbug.ashx?id=20a658ae-d7c3-4b0e-808f-59472db7098b" /&gt;</description>
      <comments>http://www.controlsystemworks.com/blog/CommentView,guid,20a658ae-d7c3-4b0e-808f-59472db7098b.aspx</comments>
      <category>historical data</category>
      <category>performance</category>
    </item>
    <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>