Skip to content

Instantly share code, notes, and snippets.

@matehat
Forked from jpsim/LevelDB.m
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matehat/27ff28ddd67b2deb499c to your computer and use it in GitHub Desktop.
Save matehat/27ff28ddd67b2deb499c to your computer and use it in GitHub Desktop.
#import <Objective-LevelDB/LevelDB.h>
#import <Objective-LevelDB/LDBWriteBatch.h>
#include <mach/mach_time.h>
#include <stdint.h>
NSString *randomString(NSUInteger length) {
NSMutableString *string = [NSMutableString stringWithCapacity:length];
for (int i = 0; i < length; i++) {
[string appendFormat:@"%C", (unichar)('a' + arc4random_uniform(25))];
}
return string;
}
void benchmarkLevelDB(NSUInteger approach) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *dbPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"test.ldb"];
[[NSFileManager defaultManager] removeItemAtPath:dbPath error:nil];
NSUInteger numberOfObjects = 30000; // 30,000
NSMutableArray *randomStrings = [NSMutableArray arrayWithCapacity:numberOfObjects * 9];
NSInteger stringLength = 10;
for (NSInteger i = 0; i < numberOfObjects * 9; i++) {
[randomStrings addObject:randomString(stringLength)];
}
const uint64_t startTime = mach_absolute_time();
// Create 30k LevelDB objects
// Precomputes random strings
LevelDB *ldb = [LevelDB databaseInLibraryWithName:@"test.ldb"];
if (approach == 0) {
// Benchmark: 1.93 seconds (!) on iPhone 5
ldb.encoder = ^ NSData * (LevelDBKey *key, NSArray *values) {
return [NSJSONSerialization dataWithJSONObject:values options:0 error:NULL];
};
LDBWritebatch *wb = [ldb newWritebatch];
for (NSInteger i = 0; i < numberOfObjects; i++) {
NSArray *subArray = [randomStrings subarrayWithRange:NSMakeRange(i * 9, 9)];
[wb setObject:subArray forKey:[@(i) stringValue]];
}
[wb apply];
} else if (approach == 1) {
// Benchmark: 10.1 seconds on iPhone 5
ldb.encoder = ^ NSData * (LevelDBKey *key, NSString *value) {
return [value dataUsingEncoding:NSASCIIStringEncoding];
};
LDBWritebatch *wb = [ldb newWritebatch];
for (NSInteger i = 0; i < numberOfObjects; i++) {
NSArray *subArray = [randomStrings subarrayWithRange:NSMakeRange(i * 9, 9)];
for (NSUInteger j = 0; j < 9; j++) {
[wb setObject:subArray[j] forKey:[NSString stringWithFormat:@"%ld.%ld", (long)i, (long)j]];
}
}
[wb apply];
}
const uint64_t endTime = mach_absolute_time();
const uint64_t elapsedMTU = endTime - startTime;
// Get information for converting from MTU to nanoseconds
mach_timebase_info_data_t info;
mach_timebase_info(&info);
// Get elapsed time in nanoseconds
const double elapsedNS = (double)elapsedMTU * (double)info.numer / (double)info.denom;
[ldb close];
NSLog(@"adding %lu objects to LevelDB took %.2f seconds", (unsigned long)numberOfObjects, elapsedNS / 1000000000.0f);
}
Just a quick performance comparison between LevelDB and Realm. Benchmark inserted 30k objects with 9 string properties each, with random strings.
Realm was **3.7 seconds** on average.
LevelDB was **73.6 seconds** on average.
#include <mach/mach_time.h>
#include <stdint.h>
#import <Realm/Realm.h>
@interface ANISampleRealmModel : RLMObject
@property (nonatomic, copy) NSString *testString1;
@property (nonatomic, copy) NSString *testString2;
@property (nonatomic, copy) NSString *testString3;
@property (nonatomic, copy) NSString *testString4;
@property (nonatomic, copy) NSString *testString5;
@property (nonatomic, copy) NSString *testString6;
@property (nonatomic, copy) NSString *testString7;
@property (nonatomic, copy) NSString *testString8;
@property (nonatomic, copy) NSString *testString9;
@property (nonatomic, assign) NSInteger testInteger;
@end
@implementation ANISampleRealmModel
@end
NSString *randomString(NSUInteger length) {
NSMutableString *string = [NSMutableString stringWithCapacity:length];
for (int i = 0; i < length; i++) {
[string appendFormat:@"%C", (unichar)('a' + arc4random_uniform(25))];
}
return string;
}
NSArray *generateRandomRealmObjects(NSInteger count) { // in this case: 30,000
NSMutableArray *objects = [NSMutableArray arrayWithCapacity:count];
NSInteger stringLength = 10;
for (NSInteger i = 0; i < count; i++) {
ANISampleRealmModel *model = [[ANISampleRealmModel alloc] init];
model.testString1 = randomString(stringLength);
model.testString2 = randomString(stringLength);
model.testString3 = randomString(stringLength);
model.testString4 = randomString(stringLength);
model.testString5 = randomString(stringLength);
model.testString6 = randomString(stringLength);
model.testString7 = randomString(stringLength);
model.testString8 = randomString(stringLength);
model.testString9 = randomString(stringLength);
[objects addObject:model];
}
return objects.copy;
}
void benchmarkRealm(void) {
[[NSFileManager defaultManager] removeItemAtPath:[[RLMRealm defaultRealm] path] error:nil];
NSUInteger approachType = 0; // 0 == slow, 1 == fast
NSUInteger numberOfObjects = 30000; // 30,000
NSMutableArray *randomStrings = [NSMutableArray arrayWithCapacity:numberOfObjects * 9];
NSInteger stringLength = 10;
for (NSInteger i = 0; i < numberOfObjects * 9; i++) {
[randomStrings addObject:randomString(stringLength)];
}
const uint64_t startTime = mach_absolute_time();
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
if (approachType == 0) {
// Approach where Realm objects are added one by one to an NSMutableArray
// and then that NSMutableArray is iterated over one by one to add each Realm object
// to the realm
// Benchmark: 20 seconds on iPhone 5 (19.67, 20.01, 19.71, 19.87, 20.99, 20.41)
NSArray *realmObjects = generateRandomRealmObjects(numberOfObjects);
[realmObjects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[realm addObject:obj];
}];
} else {
// Approach where random strings are pre-computed and
// Realm objects are created and added directly to the realm, never copied
// Benchmark: 3.7 seconds on iPhone 5 (3.35, 3.71, 3.93, 3.65, 3.77, 3.74)
for (NSInteger i = 0; i < numberOfObjects; i++) {
NSArray *subArray = [randomStrings subarrayWithRange:NSMakeRange(i * 9, 9)];
ANISampleRealmModel *model = [[ANISampleRealmModel alloc] init];
model.testString1 = subArray[0];
model.testString2 = subArray[1];
model.testString3 = subArray[2];
model.testString4 = subArray[3];
model.testString5 = subArray[4];
model.testString6 = subArray[5];
model.testString7 = subArray[6];
model.testString8 = subArray[7];
model.testString9 = subArray[8];
[realm addObject:model];
}
}
[realm commitWriteTransaction];
const uint64_t endTime = mach_absolute_time();
const uint64_t elapsedMTU = endTime - startTime;
// Get information for converting from MTU to nanoseconds
mach_timebase_info_data_t info;
mach_timebase_info(&info);
// Get elapsed time in nanoseconds
const double elapsedNS = (double)elapsedMTU * (double)info.numer / (double)info.denom;
NSLog(@"adding %lu objects to the realm took %.2f seconds", (unsigned long)numberOfObjects, elapsedNS / 1000000000.0f);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment