Friday, November 4, 2016

Optimizing C++ android code for minimum size

Any more or less serious Android  C++ code (NDK) will immediately bring a huge piece of C++ stdlib into your native library, something like 150kb+ surplus per ABI (cpu arhitecture).
Even such as this:
char *data = new char[1000];
More funny example is having a huge complex C++ class defined (several kloc including several subclases), which is producing like 30kb binary when stack-instantiated ("MyClass obj;"), and like 200kb binary when created using "new" operator ("MyClass *obj = new MyClass()").

Long story short this all happens due to a huge amount of exception handling code (which invokes iostream and other bullshit)  linked to your code due to just a single "new" operator (to handle bad_alloc exceptions), and yes, -fno-exceptions won't help you at all.

Solution is to link against minimal system STL (the only one built with no exceptions code for new/delete), by modifying your (if you are using plain NDK build) with the following line (there are a lot examples on the net):
APP_STL := system
I wasn't able to find ready solution for the modern Gradle (Android Studio) + CMake case, so had to spend a bit of time studying this fairly bad documented stuff. Finally, here we go, a piece of config you came here for (place it into your module gradle file) undo "android.defaultConfig.externalNativeBuild.cmake" element:
Technically a ADROID_STL parameter definition should be enough, but I was still getting a rogue
"cxx-stl\gnu-libstdc++\4.9\libs\...\libsupc++.a" library sneaking into my linking command, so standard libraries override came to fix.

While we are here:
 Adding these lines to your CMakeLists.txt should hide your exports not marked with JNIEXPORT, and MAY BE enable link-time-compilation/optimization for some ABIs (third line, notice library name argument). Might save you a few KBs as well (hiding non marked exports is a good thing anyway).

Tuesday, May 3, 2016

Limiting MongoDB memory usage with cgroups on Ubuntu 14.04

MongoDB is memory mapping database files, so you Free RAM won't last long. It might be fine if you believe in Linux Memory Management, however I feel quite anxious when mongod takes every single bit of 512Mbytes of RAM of my small DigitalOcean (3 month 1core/512M/20G VPS for 5$, yes 5 bucks) box. Yes I'm chip and I don't want my nginx or nodejs to starve.

Ok, so there is a solution to this - cgroups. Unfortunately there are no config templates with cgroups packages (at least for Ubuntu 14.04), this makes the topic quite obscure. I written some small bash script which will ask you for desired MongoDB memory limit, create configs and init scripts and restart services.
IMPORTANT. This shell script will overwrite all your existing cgroup configuration and init files, please make sure you have nothing to loose.

sudo bash -c 'curl -o- | bash'

You can find a good write-up on topic here, but it doesn't contain init scripts, so your changes won't last a reboot:

A good page on cgroups with Ubuntu 14.04 is here, but it contains no MongoDB specifics:

Friday, March 4, 2016

Creating delegate declared as internal in thirdparty library

Creating delegate declared as internal in thirdparty library (like mscorlib.dll) can be tricky, especially if it takes or returns arguments (classes) also declared as internal. It is pretty easy to use prepared delegate value to replace it somewhere in library internals using reflection, but attaining such delegate for your own method is completely different beast.

Lets look for example at SocketHandler delegate (mscorlib.dll):

internal delegate SocketHandler SocketHandlerFactory(
  Socket socket,
  SocketCache socketCache,
  String machineAndPort);

Beside the internal delegate itself (which we can't reference), we also have issue with SocketCache argument and SocketHandler return types both declared as internal (so we can't declare method to suit this delegate).
Long story short, the only way I found to achieve this is using DynamicMethod class which allows to declare a new method, with arguments we get from original delegate using reflection, emit some IL code to invoke our hardcoded method with untyped (object) arguments, and create delegate based on provided type.
Below there are some cuts from source code which should give you the general idea (yeah, I'm to lazy to provide full working example or fix variables names for you). Let's say we have object of SocketCache type (which has _handlerFactory delegate field we want to replace):

var sct = socketCache.GetType();
// get field info
var miHandlerFactory = sct.GetField("_handlerFactory"
  BindingFlags.NonPublic | BindingFlags.Instance);
// get variable original value  (delegate)
var oldHandlerFactory = miHandlerFactory.GetValue(socketCache);
// get type of delegate
var hft = oldHandlerFactory.GetType();
// get MethodInfo for delegate method
var hfmi = hft.GetProperty("Method").GetGetMethod()
  .Invoke(oldHandlerFactory, null) as MethodInfo;

// we will create delegate bound to our SocketFactoryInterceptor object
var sfit = typeof (SocketFactoryInterceptor);

// create dynamic method with our object as owner and a copy of all arguments of delegate
DynamicMethod dm = new DynamicMethod("Handler", hfmi.ReturnType,
  new []{sfit}.Concat(hfmi.GetParameters().Select(p=>p.ParameterType))
  .ToArray(), sfit, true);

var ilg = dm.GetILGenerator();
// load all provided arguments onto stack
foreach (var a in dm.GetParameters().Select((p,i)=>i)) 
  ilg.Emit(OpCodes.Ldarg, a);
// invoke our method (which can declare argument as simple untyped objects)
ilg.EmitCall(OpCodes.Call, sfit.GetMethod("CreateSocketHandler"), null);
// we need that cast for our predefined method to be able to return simple object type
ilg.Emit(OpCodes.Castclass, hfmi.ReturnType);

// interceptor class will do all the stuff (call original handler and do our logic), so we just need
// to pass control to our existing method - as little IL as possible
var sfi = new SocketFactoryInterceptor() { transportSink = ns, 
  socketCache = socketCache, miHandlerFactory = miHandlerFactory, 
  handlerDelegate = (Delegate) oldHandlerFactory, dynamicMethod = dm, };
// create delegate based on delegate type information we got from variable
var dlg = sfi.ourDelegate = dm.CreateDelegate(hft, sfi);

// replace variable value with our new delegate
miHandlerFactory.SetValue(socketCache, dlg);

Sunday, August 2, 2015

Extra rinse in Electrolux (AEG, Zanussi) dishwashers

Тоже самое на русском читать тут :)

Finding how to enable Extra Rinse in current models of dishwashers is very hard for causal user (although in the past it was described in manuals or even through separate button). This is, most likely, just another consequence of fight for ecology. Although I really like our planet I prefer dishes not smelling with detergent at the cost of 1-2 litters of fresh water (we are spending much more for each flush of the toilet). 
So after we bought Electrolux dishwasher I spent heaps of time (probably around 10 hours in total) finding information on how to enable Extra Rinse or even a simple not-outdated service manual. Well, you are lucky enough to read it in my post below :)

Ok, I've got ESL97610, but as far as I can tell this should work very similar in other models of close generations (like ESL6601 ESL6301 etc):
1. Turn on dishwasher
2. Press and hold first and third button together (counting from the left side, where the screen normally is, not counting On/Off button) for 4 seconds
3. LEDs above first 3 buttons will start blinking
4. Press first and second button together
5. Screen will display E0 or E1 (extra rinse Off or On, 1 = On)
6. You can switch the setting using the first button
7. Save your selection by turning your dishwasher Off with On/Off button

Instruction for earlier models (circa 2002, like EDW1000, which is readily available from everywhere on internet) were saying to press button 1 and 3 before turning the appliance on (with the rest of instruction being the same), and that small change cost me a lot of time :) It is  easy to understand why that was changed - old appliances were using push buttons and not sensor ones like in current models :)

Instruction for my model (or similar ones) was find by googling "EDW1953 manual", with EDW1953 being an electronic board version. It is available for download from here (or my mirror).
You can look for version of your electronic board in spare parts shops (like this one for electrolux), or in some technical or educational materials like this. is also a good source of manuals (just search for part of the name like ESL).

Some keywords for google: EDW1953 EDW1753 EDW1503 EDW1103 EDW4013 EDW500 EDW503 EDW1900 EDW2200 Extra rinse rinse+ Electrolux Zanussi AEG EDW1XXX EDW1953 EDW1753 EDW1503 Service Manual Сервисная ESL ESL6351 ESL6601 ESL97610 Dishwasher ESL6552RA ESL6550RO ESL6551RO ESL6601RA ESL96361LO ESL6381RA ESL98330RO ESL7320RA ESLP6815RA ESL97610RA ESL98510RO ESL96211LO ESL9531LO ESL6380RO ESL95201LO ESL97310RO ESL6392RA ESL6552RO ESL96351LO ESL98310RA ESL7310RA ESL97510RO ESL6810RO ESL98810RA ESL6810RA ESL95330LO ESL6601RO

Tuesday, July 23, 2013

GRUB in ur face

Sometimes it is really hard to find very simple information.

If you compiled GRUB with your own module (for example to create BOOTX64.EFI file to use setup_var command), and suddenly on booting from this file it throws:

Welcome to GRUB!

incompatible license
Aborted. press any key to continue.

Don't worry and just insert GRUB_MOD_LICENSE("GPLv3+"); into your .c source code.
It means nothing else.
Now you know what I feel after spending almost an hour for inventing that solution (since googling didn't help :()...

Sunday, May 5, 2013

KB2670838 issues

Just experienced Aero Glass missing, Calculator broken ( :-O ) and other windows UI issues after installing KB2670838 (as part of IE10 installation) on friends laptop. I was blaming video drivers since it has U3600 processor (integrated Intel HD video) and was already going to uninstall dreaded update, so god bless I noticed post on dpreview forum linking possible KB2670838 issues to FastPictureViewer Codec Pack. I had no codec pack, but uninstalling FastPictureViewer itself solved the problem immideatly (after restarting Desktop Windows Manager). 

I also saw post linking KB2670838 to some 3d party USB Video driver installed (not even device plugged in), so if you are experiencing such troubles I would recommend uninstall all 3d party video drivers and codec packs first before rolling back IE10 and linked updates.

Saturday, March 3, 2012

BSOD 0x0000007B 0x0000006B

Just got a situation when computer I was trying to help with was constantly throwing Blue Screens Of Death with codes 0x0000007B and 0x0000006B during Windows XP start, Alkid SD start, and even Windows XP setup start.

Solution was simple: two cd-roms sitting on one Paralel ATA cable both in slave mode. :)