NAVmoble - the pocket-sized ERP
Optimized for Microsoft Dynamics NAV and Windows Mobile powered devices

Wednesday, November 30, 2005

The first portable computer

While reading around, I was able to find a proof about how fast the technology goes forward. See a picture of the first "portable" computer called Osborne-1, created in 1981. It was sized to fit under an airplane seat and was armed with Basic,WordStar and SuperCalc. So it seems you had to buy an airplane to carry it. Now we buy bags and belts and pants with pockets. :)

Monday, November 21, 2005

SKU Matrix for Windows Mobile Version 5.0

Are you a looking for a Windows Mobile 5 brief feature list?
This is the place where you may start reading

Sunday, November 20, 2005

.NET Compact Framework 2.0 Performance and Reflection

   If you spent your time researching performance improvement tips, soon you will find that reflection is a great but expensive feature in terms of performance.
Let's see some metrics, then!
   My test environment is just the same as in my previous post
We've got HTC QTEC 9090, VS2005,CF2.0,Sql Ce 3.0.
I used the same database structure and 10000 rows to fetch. Every scenario makes 5 subsequent runs. Application is restarted before each test scenario run. Scenario 1 is not listed here , because it uses DataRow instances to represent database table rows.
The code is almost the same. I changed only the way the BObject instance is created. It is created by using Activator.CreateInstance method, this time.

List<BObject> boList = new List<BObject>();
...
IDataReader reader = cmd.ExecuteReader();
...
while(reader.Read())
{
//This was the old instance creation
//BObject bo = new BObject();


//This is the new extra time-consuming instance creation
BObject bo = (BObject)Activator.CreateInstance(typeof(BObject));
bo.id = reader.GetInt32(0);
bo.data1 = reader.GetString(1);
bo.data2 = reader.GetDateTime(2);
bo.data3 = reader.GetDouble(3);
boList.Add(bo);
}


I repeated the same testing scenarios and here come results:
Scenario 2: SqlCeDataReader
#Time[ms]Memory[bytes]Time increase[%]
11006496221699
283441125212142
382611295408136
482881422712143
58333952280129

Scenario 3-a:SqlCeResultSet,None
#Time[ms]Memory[bytes]Time increase[%]
11057696206497
290911125200133
390291295396131
490621422700129
59019952128133

Scenario 3-b:SqlCeResultSet,Insensitive
#Time[ms]Memory[bytes]Time increase[%]
115486996206427
214016112520029
313886129539628
414118142270029
51410595212830

Scenario 3-c:SqlCeResultSet,Scrollable,Updatable,Sensitive
#Time[ms]Memory[bytes]Time increase[%]
11405496206442
212494112520070
312369129539664
412471142270065
51240695212867


   We've got ~25-140 percents time increasing, due to using this resource hungry feature! There is also a small memory overhead. It is not as meaningful as the time increase. However the memory increase was stable across all the test scenario runs, that I've performed. It is interesting that testing scenarios 2 and 3-a(the faster data access methods) report far greater time increasing compared with the rest ones. The time diff. between scenario 3-a and 3-b in the previous test cases had a mean value of ~60%. In this case the diff. is only ~30% due to performance loss in scenario 3-a.
   One of the reasons, which motivated me to perform these tests was that Activator.CreateInstance pattern is very useful, when extendability and flexibility are required.
And while this pattern is frequently used in the desktop environment, it comes with a great cost in the CF world.

Saturday, November 12, 2005

.NET Compact Framework 2.0 Data Access Performance

Further reading .NET Compact Framework 2.0 Performance and Reflection

I took little of my time today to prepare a VS2005 SD project to test the performance differences between some of the SqlCe data access options. I have the following test environment:
Device: HTC QTEK 9090
OS: Windows Mobile 2003 SE
Dev.Env: VS2005 , CF2.0,SqlCe 3.0
I've created a table with the following Sql:

CREATE TABLE test1
(
id int IDENTITY NOT NULL,
data1 nvarchar(100),
data2 datetime,
data3 float
)


I've populated it with 10000 rows, using the following Sql:
insert into test1(data1,data2,data3)values('some string',getdate(),123)
I measured then the performance, while reading rows from SqlCe 3.0 by using the following testing scenarios:

scenario 1: DataSet, SqlCeAdapter
scenario 2: SqlCeDataReader
scenario 3-a: SqlCeResultSet, options None
scenario 3-b: SqlCeResultSet, options Insensitive
scenario 3-c: SqlCeResultSet, options Sensitive,Updatable, Scrollable

All scenarios were played using the following Sql statement:
SELECT id,data1,data2,data3 FROM test1

There is a significant difference between the first scenario and the rest ones. Scenario 1 fetches all rows into a DataSet. The rest fetch
rows into object instances defined like:
public class BObject
{
public int id;
public string data1;
public datetime data2;
public double data3;
}

The fetching code was like:
List<BObject> boList = new List<BObject>();
...
IDataReader reader = cmd.ExecuteReader();
...
while(reader.Read())
{
BObject bo = new BObject();
bo.id = reader.GetInt32(0);
bo.data1 = reader.GetString(1);
bo.data2 = reader.GetDateTime(2);
bo.data3 = reader.GetDouble(3);
boList.Add(bo);
}

Every scenario was executed 5 times and execution time and total memory reported by GC were written down. The application was restarted before each scenario test run. The results are as follows:
Scenario 1:DataSet
#Time[ms]Memory[bytes]
1101122096016
286731930176
385922189796
486562096160
586541930176

Scenario 2: SqlCeDataReader
#Time[ms]Memory[bytes]
1506952548
234531051124
334941151748
43414850952
53639953004

Scenario 3-a:SqlCeResultSet,None
#Time[ms]Memory[bytes]
15368952536
239041051156
339021151692
43964850896
53875952992

Scenario 3-b:SqlCeResultSet,Insensitive
#Time[ms]Memory[bytes]
112238952536
2108481051156
3108261151692
410917850896
510877952992

Scenario 3-c:SqlCeResultSet,Scrollable,Updatable,Sensitive
#Time[ms]Memory[bytes]
19928952536
282661051156
384441151692
48538850896
58460952992

What is obvious from first sight is that SqlCeResultSet has different performance characteristics depending on the options used. Also you may see that DataSet is on the first place in memory consumed. One interesting figure is the longer time neededd to execute test run 1 and that's because of the JIT compiling proces on the first code hit.It seems from this tests that using SqlCeReder should be preferred in strict fetching scenarios, although perf differenceses from SqlCeResultSet(None) are not quite meaningful. However, if one needs scrolling and updating, SqlCeResultSet is the best choice.Unfortunately, I have not written down the perf. status of the system componentsts like SqlCe memory, total system memory used ,etc.This will help getting better picture of the data access pros and cons.

Wednesday, November 09, 2005

VS2003-To-VS2005 Solution conversion failure

I tried to convert my VS2003 SmartDevice solution to VS2005. Unfortunately, the conversion wizard faled with message "Compact Framework 1.0 is not installed."I was in a hurry so decided just to solve the problem.( I have CF 1.0 installed, actually!I was even able to create and run CF1.0 solution with VS2003 in order to see if it still works).Anyway I found the following resolution:

After conversion falure you will see your VS2005 solution having all projects marked as "Unavailable".
In order to fix the problem perform the following steps:

  1. Click the right mouse button over the project in Solution Explorer. Select"Edit xxxxxx.csproj" - it opens the project file source.
  2. Locate tag TargetFrameworkVersion and change tag content from "v1.0" to "v.2.0"3.
  3. Click the right mouse over the project in Solution Explorer again and select "Reload project." Conversion wizard will open again and you will have your project in VS2005 format.
    This does not mean you will be able to compile it. You may have to spent some more time to solve some other issues :(


Compact Framework Performance Hints

Performance is a big pain in the CF world. Here comes some
usefull general performance hints when using CF 1.0/2.0.

1. Avoid virtual calls when not needed.
Virtual calls are slower that instance and static calls. CF 1.0 virtual calls are interpreted at runtime due to the working set cost(vtables are not used). This cause about 40% slower performing virtual calls compared to statis and instance calls. Interpreted virtual calls are cached in a fixed length cache. CF 2.0 uses a variable size cache which leads to nearly 100% hit rate. Anyway, avoid using virtual calls if not needed.

2. Avoid properties
Properties are slower than field. It may happen compiler to inline property getters and setters but do not dont trust it. CF 2.0 propose better performance on virtual properties due the upper mentioned changes.

3. Avoid PInvoke.
It is up to ~6 times more expensive than managed instance calls.

4.Override Equals() and GetHashCode()
Built in behavior of Equals() and GetHashCode() uses reflection, which leads to extra performance impact. Create your own optimized implementations.

5. Explicit string intern.
It may help optimizing performance, however do not use it ( and trust the builtin interning mechanism)unless you are not sure that it helps. Intern process may bring extra performance penalties if not used properly

6.Method inlining.
Although, it is not easy to predict if the JIT compiler will inline particular method, it may be beneficial trying to make the method a candidate for inlining:
Method must have:
- 16 bytes of IL or less
- No branching
- No local vars
- No exception handlers
- No 32 nit floating argument ot ret values
- Using of arguments in their declaration order
And do not use debugger:)

7. Enregistration
CF 2.0 introduces enregistration- a process of storing 32 bit sized (locals and arguments) into the CPU registers. This leads to significant performance improvement however you should stick with 32 bit sized variables. Less sized variable may not be as efficient as 32 bit due to additional
conversion issues.

8.Garbage Collection
In general GC is expensive process from a performance point of view.
Try to avoid creation of too mach managed objects - for example try to avoid boxing/unboxing operations, poorly written string manipulations, etc. In order to diagnose GC issues lookup "GC Latency Time" perf. counter in mscoree.stat Cf 2.0 allows runtime perf log emit, which may help to better diagnostic/monitoring solutions.

9.Use ThreadPool
If you have a big number of short living async workers using of ThreadPool will help application to perform better.

10.Parsing DateTime
Use DateTime.ParseExact method to parse DateTime.Otherwise a variety of culture specific conversions will be applied until the right one is found.

11.Some common hints
- Avoid iterators - use indexers
- Pre-resize collections
- Avoid boxzing/unboxing
- Use specialized classes for string operations
- Use typed collections for best performance. Extensive generics
usage may increase JIT pressure, which may cause performance penalties depending on the number of the types/generics defined combinations.

12. Xml
-Use XMLReader and XmlWriter for Xml processing
-Don't use schema parsing unless you must.
-Design shorter documents: strip white spaces,use attributes
-Use Skip(), where possible - it is faster than Read()
-Use factory classes XMLReader/XMLWriter to create a proper optimized reader/writer
-Use XmlReaderSettings and XmlWriterSettings classes to get
better optimized readers/writers
-Avoid Windows codepage encodings - Use UTF8 or ASCII
-Create single XmlSerializer per type and cache it for next use.
XmlSerializer serializier creation is expensive

13. Datasets
-Use typed DataSets
-Avoid DateTime columns - use Ticks instead.
-Avoid storing Datasets as Xml - store schema as well if it may not be avoided.
-Use schema, when DataSet loading is done from Xml
-Map columns as attributes when loading DataSet from Xml

14. Data
- Avoid DataSets
- Use DataReader and Sql Server Ce
- Dispose SqlCeCommand and DataReaders

15.WebServices
-Create single WebService proxy instance and use it during the whole application
life cycle in order to avoid first-hit proxy reflection.
-Avoid sending DataSets across the network
- Use DiffGrams if DataSets usage is required.

17. Avoid reflection
Although reflection may give applications flexibility it is quite resource-hungry feature.
Do not use it if possible.

18. GUI
- Load and cache Forms in background
- Do not populate data on Form.Show(). Do it async
- Use SuspendLayout/Resume Layout, when repositioning controls
- Be carefull, when using events
- Use background processing

Details may be found on .NET Compact Framework Team's Blog

Tuesday, November 08, 2005

Sofia .NET User Group Meeting

The next Sofia .NET User Group meeting is going to be on 12.Nov.2005/11.00h at FMI (Sofia's University). The event is organized together with BARS
This time it will be a whole day event dedicated to the VS2005 launch.
We will have 3 great presenters and they will going to talk about :

No doubt it will be a great event!

Tuesday, November 01, 2005

NavMobile - pocket size ERP

We are going to present our new mobile product at BAIT Expo 2005
The product is a result of the joined efforts of RITSoftware and Intelligent Systems.
It is called NavMobile and acts as a ERP mobile front-end and targets multiple ERP systems.

The platform is build over Compact Framework on the mobile side and targets Pocket PC devices. It provides instrumentation for rapid on site customization, smart synchronization, remote monitoring and configuration and more.

Everybody may meet us between 1 and 6.Nov.2005 at Inter Expo Center-Sofia, hall 3,3B10

Stay tuned for more details ...