Benchmarking in Objc
This post hasn't been updated for 8 years
Phát triển một ứng dụng, ngoài việc có giao diện đẹp, chức năng hay, một yếu tố không thể thiếu đó là performance của ứng dụng. Bất kì một lập trình viên có tâm nào cũng sẽ lưu ý tới việc làm cho ứng dụng của mình chạy nhanh hơn. Tuy nhiên, việc này hoàn toàn không dễ dàng một chút nào.
Ngày này, các lập trình viên ứng dụng làm việc với các ngôn ngữ bậc cao (Objective-C, Swift). Việc này đồng nghĩa với việc chúng ta sẽ phải giải quyết các logic xử lý ở tầng người dùng, mà đôi khi bỏ quên các tiểu tiết - những thứ có thể sẽ ảnh hưởng ít nhiều tới performance của ứng dụng.
Benchmarking , là một công cụ cần thiết cho bất kì một lập trình viên nào để giúp ứng dụng chạy nhanh hơn.
Benchmarking performance trong Objective-C
Cách thức khoa học để có thể thực hiện benchmark sẽ được tiến hành theo các qui trình sau :
- Đặt ra các câu hỏi.
- Xây dựng các giả định.
- Dự đoán kết quả.
- Kiểm tra các giả định
- Phân tích kết quả.
Trong lập trình, về cơ bản ta hỏi như sau :
- Hàm, hoặc phương thức tập trung vào việc tính toán hay lưu trữ ?
- Với các qui mô khác nhau của dữ liệu thì hành vi sẽ như thế nào ?
- Cái nào nhanh hơn?
Dưới đây là một số công cụ cho Markbench trên Obj-C
** I, CACurrentMediaTime ** Trong ví dụ này, chúng ta sẽ thử với việc adding object vào một mutable array.
static size_t const count = 1000;
static size_t const iterations = 10000;
id object = @"test"
Chúng ta đơn giản sẽ tính toán khoảng thời gian trước và sau khi thực hiện phương thức, việc sử dụng CACurrentMediaTime() , hoặc mach_absolute_time() sẽ tiện lơi hơn rất nhiều, không giống như NSDate() hoặc CFAbsoluteTimeGetCurrent(), hai phương thức trên hoàn toàn không bị ảnh hưởng bởi các yếu tố như Time zone, daylight saving ..
CFTimeInterval startTime = CACurrentMediaTime();
{
for (size_t i = 0; i < iterations; i++) {
@autoreleasepool {
NSMutableArray *mutableArray = [NSMutableArray array];
for (size_t j = 0; j < count; j++) {
[mutableArray addObject:object];
}
}
}
}
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
** II, dispatch_benchmark ** là một phương thức của libdispatch a.k.a Grand Central Dispatch , phương thức này không được public, tuy nhiên bạn vẫn có thể sử dụng cho mình
extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));
Thay vì viết như trên kia, ta sẽ viết lại như thế này :
uint64_t t = dispatch_benchmark(iterations, ^{
@autoreleasepool {
NSMutableArray *mutableArray = [NSMutableArray array];
for (size_t i = 0; i < count; i++) {
[mutableArray addObject:object];
}
}
});
NSLog(@"[[NSMutableArray array] addObject:] Avg. Runtime: %llu ns", t);
Nhìn có vẻ ngon hơn nhỉ ? Nanoseconds và cú pháp block ?
** [NSMutableArray array] vs [NSMutableArray arrayWithCapacity] ??? ** Chúng ta sẽ thử sử dụng cách thức trên để đo xem trong hai hàm khởi tạo kia, hàm khởi tạo nào thực thi nhanh hơn. Đây là một câu hỏi là không phải ai cũng biết.
uint64_t t_0 = dispatch_benchmark(iterations, ^{
@autoreleasepool {
NSMutableArray *mutableArray = [NSMutableArray array];
for (size_t i = 0; i < count; i++) {
[mutableArray addObject:object];
}
}
});
NSLog(@"[[NSMutableArray array] addObject:] Avg. Runtime: %llu ns", t_0);
uint64_t t_1 = dispatch_benchmark(iterations, ^{
@autoreleasepool {
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:count];
for (size_t i = 0; i < count; i++) {
[mutableArray addObject:object];
}
}
});
NSLog(@"[[NSMutableArray arrayWithCapacity] addObject:] Avg. Runtime: %llu ns", t_1);
Kết quả chỉ ra là :
[[NSMutableArray array] addObject:]: Avg. Runtime 26119 ns
[[NSMutableArray arrayWithCapacity] addObject:] Avg. Runtime: 24158 ns
Sự khác biệt rơi vào khoảng 7% nhanh hơn, không thực sự lớn nhưng biết thêm một chút thông tin cũng thú vị nhể ?
Chúc các bạn vui vẻ với việc đo benchmark theo cách này, ngoài ra bạn cũng có thể sử dụng Instrument để có cách đo đạc dễ dàng hơn. Thân.
All Rights Reserved