Creating DevExpress.NET toolbox icons for non-admin users
At work we use the DevExpress .NET widget toolkit to build flashy GUIs. I recently repaved my dev box, and now run as a non-admin user most of the time. This often causes problems with badly-behaved software, which apparently includes the DevExpress .NET toolkit.
If I run the installer as an admin, it creates convenient toolbox items in Visual Studio 2008 for dropping various DevExpress controls into the forms I build. However, my non-admin user doesn’t get these toolbox items. There’s a separate tool, the Toolbox Creator, which ships with DevExpress for the purpose of putting these back, but it doesn’t work without admin privs (see here).
DevExpress’s handy advise is:
The ToolBoxCreator creates toolbox icons only for the user for which it is launched. And, this user must have Administrator rights. This behavior is by design.
Besides, running the VS 2008 under a user without administrator rights leads to many issues
Well, fuck you. Maybe you can’t write code that behaves properly without admin privs, but that doesn’t mean I can’t.
I figured out a hack to get their shit working. Use Aaron Margosis’ MakeMeAdmin batch file to create a command window which is running as you, but with admin privs. cd into the DevExpress Tools directory, then run the target of the ToolboxCreator shortcut. Voila!
For the most part I’m happy with the DevExpress toolkit, but this incident really pissed me off. There’s no earthly reason why the Toolbox Creator needs admin rights, since the toolbox settings are per-user. It’s just lazy programming.
Migrating gallery from Gallery2 to Flickr
I’m finally moving apocryph.org over to FutureHosting from DreamHost. I’ve put it off for so long because my 35+GB photo gallery will be a real pain to move over, and will use most of the 40GB of storage I have allotted on one of my two VPS accounts.
I really wanted to move my photo hosting to Picasa Web Albums, on account of the awesome new face detection/recognition feature they have in beta, but in the end I was swayed by value.
Here’s the price schedule for Picasa Web Albums:
- 10 GB ($20.00 USD per year)
- 40 GB ($75.00 USD per year)
- 150 GB ($250.00 USD per year)
- 400 GB ($500.00 USD per year)
Here’s the schedule for Flickr:
- Unlimited ($24.95/yr)
Since I’m almost at 40GB, inside of a year I would be spending $250/yr for Picasa storage. Sorry, but face recognition coolness isn’t worth that sort of a premium.
I’m currently in the process of migrating my entire gallery over to Flickr using the Gallery2Flickr plug-in for Gallery 2. It’s slow going; I’ll have a separate post about the jigger-pokery required to make that work. Once I’m done, I’ll use my Gallery 2 install solely for hosting photos for my family, which is a small enough dataset that I can fit it on my VPS without difficulty.
The end of an era: Vista on a dev box, and wintermute's retirement
This weekend marked the end of a long era, and the beginning of another, presumably shorter one.
First, I finally decommissioned wintermute, the old Sony VAIO PCV-90 that’s been running OpenBSD and serving as my home network’s firewall for the last five years or so. wintermute has been in more-or-less continuous operation since I bought it, the first PC I owned, from CompUSA in Rockville, MD back in 1996. wintermute served me well for many years, including occasional car trips to visit my first geek crush for Linux hacking sessions and twinkies. After I moved on to greener pastures (boromir, I think), wintermute was handed down to my siblings, who used it until I took it back for use as my firewall.
It’s quite remarkable that it has the original mobo, RAM, processor, power supply, and network card. The hard drive was long ago replaced, and the CD-ROM stopped working somewhere around 2000, but the machine itself has been solid. Now it’ll go out to pasture in my server closet.
I didn’t want to be rid of wintermute, but my FiOS connection is just too fast for it to keep up with. During heavy torrenting CPU usage was around 60% interrupt, and its 64MB of RAM weren’t enough to handle thousands of NAT state table entries and run DHCP and DNS for my network. boromir has now filled the role, with a screaming Pentium II 300MHz processor and 160MB of RAM, which is likely to suffice for quite some time.
On another, more pathetic note, I repaved wyoh, my primary laptop, to run Vista Ultimate x64. I held out as long as I could, but Windows XP x64 edition’s crap hardware support and non-existent game support made it harder and harder to live with. As much as I’d like to sell all my earthly possessions and switch to Ubuntu, the people that pay me like me to develop Microsoft software, which is something of a PITA on Ubuntu, and before you suggest I do my development inside a VM, fuck yourself and go try it for a day before you get all high and mighty.
I already hate Vista’s huge performance penalty, and the Aero eye candy doesn’t make up for it. I look forward to inexplicable lags and sputters as all the various anti-piracy tilt bits wobble about, lest I use my computer how I see fit to use it, without regard for the wishes of my betters. Hopefully, in the future, Microsoft will dissipate into irrelevance and I can get paid to run Linux like all the cool kids, but until then, you run what you brung.
An analysis of Ruby 1.8.x HTTP client performance
Not too long ago I bitched about the performance of Ruby’s HTTP client. Some of the comments to that post prompted me to investigate this further, in the hopes of finding a more performant implementation solution.
The results of my analysis are in, and they’re…interesting, to say the least.
Summary
Ruby 1.8.6 (which still seems the dominant version among both Linux binary packages and the Windows One-Click Installer) uses a hard-coded 1K buffer size for HTTP reads, which leads to a ton of CPU usage during large HTTP downloads, even though the operation should be I/O bound and barely touch the CPU.
Ruby 1.8.7 includes a change described by the following entry in the changelog:
Mon Mar 19 11:39:29 2007 Minero Aoki <aamine@loveruby.net>
* lib/net/protocol.rb (rbuf_read): extend buffer size for speed.
After this change, Ruby’s HTTP implementation now uses a hard-coded 16K buffer, in the hopes of improving performance. Whether or not this actually improves things will become clear in my analysis later on.
In addition to Ruby’s built-in Net::HTTP client, I evaluated two alternatives: a version of the rfuzz HTTP client modified to support streaming GETs, and curb, the Ruby bindings for the native libcurl HTTP client library. My goal was to determine the best-case Ruby HTTP client performance as indicated by the performance of these two implementations, then munge Ruby’s stock implementation to try to approach the best-case performance.
rubyhttp
I wrote a tool, rubyhttp, to help me perform these tests. The code is freely available at my SVN repository at http://svn.apocryph.org/svn/projects/rubyhttp/trunk. To grab the code, do a svn co http://svn.apocryph.org/svn/projects/rubyhttp/trunk. The tests below were run with revision 127 of the code.
Test environment
I ran the tests on two machines: wyoh, a Windows XP x64-edition Core 2 Duo laptop with a FiOS internet connection, and lio, one of my FutureHosting VPS boxes running CentOS 5.
On wyoh I used the version of Ruby that comes with the latest one-click installer:
>ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]
On lio I tested two versions of Ruby. The first was installed by the ruby yum package:
$ ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i686-linux]
As you can see, this is the same version and patchlevel as my Windows box. Once I discovered the 16k buffer enhancement in Ruby 1.8.7, I downloaded and built the latest 1.8.7 source tree. This is:
$ ~/ruby18/bin/ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux]
Test data
My test code fetches the 10MB test files published by FutureHosting for measurement of the network performance at each of their data centers. Thus, my code retrieves data from Seattle, Dallas, Chicago, Washington DC, and London. lio is located in the very same Dallas data center, hence the crazy-high download speeds there, while wyoh is located in the suburbs of Washington DC in close geographical and network proximity to the DC datacenter.
HTTP variations
Each test run does an HTTP get from five different locations, using Net::HTTP and (on Linux only) rfuzz and curb as well. Neither rfuzz nor curb could be made to work on Windows, so the Windows runs use only Net::HTTP.
Most of the tests exercise some variation in the Net::HTTP implementation. The following variations are used:
stock– As it implies, theNet::HTTPimplementation is unmodified from whatever ships with the version of Ruby being usedcustom-16kbuffer– Modifies the buffer size from 1K to 16K. Note that Ruby 1.8.7 already includes this modification, so you’ll only see this run with Ruby 1.8.6 on Windows.custom-16kbuffer-notimeout– Buffer size of 16K, and thetimeoutcall is removed. This obviously isn’t a practical change, but it demonstrates the overhead of Ruby’s appallingtimeoutimplementationcustom-16kbuffer-select– Buffer size of 16K, and thetimeoutcall is replaced with non-blocking I/O usingselect, as proposed by Tanaka Akira on the ruby-talk listcustom-16kbuffer-selectwithsysread– Buffer size of 16K, thetimeoutcall is replaced with non-blocking I/O usingselect, as proposed by Tanaka Akira on the ruby-talk list, and theread_nonblockingcall afterselectindicates the presence of data to read is replaced bysysreadcustom-64kbuffer-notimeout– Buffer size of 64K, and thetimeoutcall is removed. This obviously isn’t a practical change, but it demonstrates the overhead of Ruby’s appallingtimeoutimplementationcustom-64kbuffer-select– Buffer size of 64K, and thetimeoutcall is replaced with non-blocking I/O usingselect, as proposed by Tanaka
All of these custom variations modify lib/ruby-1.8/net/protocol.rb, which contains the socket I/O functionality used by Net::HTTP. The rbuf_full method contains the actual socket read logic.
Data
Each run outputs the following information for each combination of HTTP URL and HTTP client implementation:
- Site – name of the site (eg ‘seattle’, ‘washdc’, etc)
- Impl – name of the HTTP implementation
- KBytes Transferred
- KBytes/second
- Chunk count – The number of reads required to fetch the entire file
- Mean chunk size – The average read size
- Min chunk size
- Max chunk size
- User Time – The % of user time taken by
rubyduring the run - System Time – The % of system time taken by
rubyduring the run - Total CPU Time – The total % of CPU time taken by
rubyduring the run - Clock time – The amount of time spent downloading the file
- % CPU usage – Defined as
Total CPU Time/Clock Time*100. The percentage of available CPU time taken byruby
The raw data are available under SVN at results/linux/2008-10-4 and results/windows/2008-10-4. I used my combine_csv.rb tool to generate results/linux/2008-10-4/aggregate.csv from the individual test results. I ended up not using the Windows results as they complicated the graph and didn’t materially impact the conclusion.
I sucked aggregate.csv into Excel to do some munging.
Pretty Pictures
I uploaded the data to Swivel, thinking it would make it easy to analyze the data. It didn’t. I wanted to do a clustered bar graph, where each cluster corresponds to a site, and bars within that cluster reflect CPU usage for each implementation when downloading from that site. Swivel is way too limited for that.
The best I can so is this graph, which clusters by implementation and graphs CPU usage for each site; the opposite of what I wanted. You can play with the data yourself if you like.
Using good old fashion Excel, I generated this graph:

As you can see, the worst performers are the stock Net::HTTP implementations in both 1.8.6 and 1.8.7, though 1.8.6 is noticeably worse due to the 1K buffer size vs 16K for 1.8.7. The best performer is curb (libcurl bindings for Ruby), under with 1.8.6 and 1.8.7. The fastest Net::HTTP-based implementation uses a 16K buffer size and bypasses the timeout method, which is apparently quite inefficient. Using the non-blocking select to implement a timeout is slower than no timeout at all, but still considerably better than the stock impl. Finally, the 64k buffer size variants were actually worse performance-size than the 16K variants.
It’s also quite obvious that Dallas transfers took up the most CPU, while London took the least. What you can’t see from this graph, but would see in the raw data, is that Dallas transfers were crazy-fast (since these tests were run on the same network as the Dallas test file), so there was less wall-clock time spent on the test, thus the transfer was less I/O bound than others. For the same reason, London, by far the slowest transfer, uses the least amount of CPU. This does not mean that transfers from fast download sites are inherently less efficient. If instead of %CPU time I used the total CPU time column, this disparity would vanish.
Conclusion
Ruby’s Net::HTTP implementation blows. It’s a bit better in 1.8.7 with the new 16K buffer size, but the timeout implementation has got to go. Even with timeout eliminated, Net::HTTP is trounced by the pure-Ruby rfuzz and the native/Ruby blend curb, suggesting that timeout notwithstanding, there are other inefficiencies in Net::HTTP. Looking at the protocol.rb code, I’m struck by how painfully inefficient the implementation is with buffers. rfuzz and curb minimize buffer copies and my rfuzz streaming HTTP extension reuses the same buffer for multiple calls, while Net::HTTP is happily appending and sliceing away at arrays.
I think architecturally Net::HTTP can be saved, but it needs rewritten buffered I/O and an alternative to timeout, preferably in the form of select.
I’m going to try to work on the necessary changes, and will post whatever I come up with.
The Windows Security Model Is Ridiculous
At work I’ve been writing some code to do some basic interactions with the Windows security subsystem, such as testing if a user has the Log On As a Service privilege. Every time I venture in this area of Windows I cringe, because the security APIs are disjointed, incoherent, and vastly over-complicated. Presumably this is due to the evolution of the Windows security subsystem as it diverged from its VMS roots, but that’s no excuse.
The latest example pertains to the ‘Log on as a service’ privilege, called SeServiceLogonRight, which corresponds to a #define in the Windows SDK called SE_SERVICE_LOGON_NAME. I need to know if a given account has this privilege, because if not I need to grant it before the account can run a service. Easy, right?
You’d think so. There’s an API function, PrivilegeCheck, that will test if a given token has a set of privileges. The only problem is that PrivilegeCheck wants the privileges described as LUIDs, which are the binary identity of each privilege. All I know is the so-called “programmatic name”, that is, SeServiceLogonRight. No problem; there’s an API for that, called LookupPrivilegeValue, that returns the LUID for a privilege given its name.
So I wrote that up, but something’s wrong. LookupPrivilegeValue is failing with error ERROR_NO_SUCH_PRIVILEGE (that’s error number 1313). The text associated with that error code is A specified privilege does not exist. This is, of course, bullshit, since I got the priv name from the Windows headers.
After a bit of spelunking, though, I found this MSDN document.aspx) that notes certain privileges, including SeServiceLogonRight as well as other favorites like SeInteractiveLogonRight and SeNetworkLogonRight, are so-called “account rights”. What’s the difference between an “account right” and normal privileges? Well:
All of the LSA functions mentioned in the introduction above support both account rights and privileges. Unlike privileges, however, account rights are not supported by the LookupPrivilegeValue and LookupPrivilegeName functions.
Nice. So, how the hell do I test for this privilege–I mean–account right?
The LsaEnumerateAccountRights function enumerates the account rights held by a specified account.
Lovely. The reason that sucks is that I can pass a token from OpenProcessToken to PrivilegeCheck, but LsaEnumerateAccountRights wants a SID, plus I have to open a handle to the local security policy. Why the FUCK are account rights and privileges treated as equivalent if they have different semantics and APIs? And don’t get me started on the epic FAIL that is LSA_UNICODE_STRING!