JXPerformanceTests.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. //
  2. // JXPerformanceTests.m
  3. // AICityTests
  4. //
  5. // Feature: 003-ios-api-https
  6. // 剧星平台性能测试
  7. //
  8. #import <XCTest/XCTest.h>
  9. #import "JXPlaybackProgressStorage.h"
  10. #import "JXCountFormatter.h"
  11. @interface JXPerformanceTests : XCTestCase
  12. @property (nonatomic, strong) JXPlaybackProgressStorage *storage;
  13. @end
  14. @implementation JXPerformanceTests
  15. - (void)setUp {
  16. [super setUp];
  17. self.storage = [JXPlaybackProgressStorage sharedStorage];
  18. [self.storage clearAll];
  19. }
  20. - (void)tearDown {
  21. [self.storage clearAll];
  22. [super tearDown];
  23. }
  24. #pragma mark - 存储性能测试
  25. - (void)testPerformanceSingleProgressSave {
  26. [self measureBlock:^{
  27. NSString *episodeId = [NSString stringWithFormat:@"perf_ep_%d", arc4random()];
  28. [self.storage saveProgressWithEpisodeId:episodeId
  29. dramaId:@"perf_drama"
  30. position:arc4random() % 120000
  31. duration:120000
  32. isCompleted:NO
  33. synced:NO
  34. completion:nil];
  35. }];
  36. }
  37. - (void)testPerformanceBatchProgressSave {
  38. [self measureBlock:^{
  39. for (int i = 0; i < 100; i++) {
  40. NSString *episodeId = [NSString stringWithFormat:@"batch_ep_%d", i];
  41. [self.storage saveProgressWithEpisodeId:episodeId
  42. dramaId:@"batch_drama"
  43. position:arc4random() % 120000
  44. duration:120000
  45. isCompleted:NO
  46. synced:NO
  47. completion:nil];
  48. }
  49. }];
  50. }
  51. - (void)testPerformanceProgressQuery {
  52. // 准备测试数据
  53. for (int i = 0; i < 1000; i++) {
  54. NSString *episodeId = [NSString stringWithFormat:@"query_ep_%d", i];
  55. [self.storage saveProgressWithEpisodeId:episodeId
  56. dramaId:@"query_drama"
  57. position:arc4random() % 120000
  58. duration:120000
  59. isCompleted:NO
  60. synced:arc4random() % 2 == 0
  61. completion:nil];
  62. }
  63. [self measureBlock:^{
  64. NSString *randomEpisodeId = [NSString stringWithFormat:@"query_ep_%d", arc4random() % 1000];
  65. [self.storage getProgressWithEpisodeId:randomEpisodeId];
  66. }];
  67. }
  68. - (void)testPerformanceDramaProgressQuery {
  69. // 准备测试数据
  70. for (int i = 0; i < 500; i++) {
  71. NSString *episodeId = [NSString stringWithFormat:@"drama_query_ep_%d", i];
  72. [self.storage saveProgressWithEpisodeId:episodeId
  73. dramaId:@"drama_query_test"
  74. position:arc4random() % 120000
  75. duration:120000
  76. isCompleted:NO
  77. synced:arc4random() % 2 == 0
  78. completion:nil];
  79. }
  80. [self measureBlock:^{
  81. [self.storage getProgressByDramaId:@"drama_query_test"];
  82. }];
  83. }
  84. - (void)testPerformanceUnsyncedProgressQuery {
  85. // 准备测试数据(50%未同步)
  86. for (int i = 0; i < 1000; i++) {
  87. NSString *episodeId = [NSString stringWithFormat:@"unsynced_ep_%d", i];
  88. [self.storage saveProgressWithEpisodeId:episodeId
  89. dramaId:@"unsynced_drama"
  90. position:arc4random() % 120000
  91. duration:120000
  92. isCompleted:NO
  93. synced:i % 2 == 0 // 50%已同步,50%未同步
  94. completion:nil];
  95. }
  96. [self measureBlock:^{
  97. [self.storage getUnsyncedProgresses];
  98. }];
  99. }
  100. #pragma mark - 格式化工具性能测试
  101. - (void)testPerformanceCountFormatter {
  102. NSArray *testNumbers = @[
  103. @0, @999, @1000, @9999, @10000, @99999,
  104. @100000, @999999, @1000000, @9999999,
  105. @10000000, @99999999, @100000000, @999999999
  106. ];
  107. [self measureBlock:^{
  108. for (NSNumber *number in testNumbers) {
  109. [JXCountFormatter formatCount:[number longLongValue]];
  110. }
  111. }];
  112. }
  113. - (void)testPerformanceCountFormatterSpecificMethods {
  114. NSMutableArray *testCounts = [NSMutableArray array];
  115. for (int i = 0; i < 1000; i++) {
  116. [testCounts addObject:@(arc4random() % 1000000000)];
  117. }
  118. [self measureBlock:^{
  119. for (NSNumber *count in testCounts) {
  120. long long countValue = [count longLongValue];
  121. [JXCountFormatter formatLikeCount:countValue];
  122. [JXCountFormatter formatCommentCount:countValue];
  123. [JXCountFormatter formatShareCount:countValue];
  124. [JXCountFormatter formatFavoriteCount:countValue];
  125. [JXCountFormatter formatPlayCount:countValue];
  126. }
  127. }];
  128. }
  129. #pragma mark - 批量操作性能测试
  130. - (void)testBulkOperationPerformance {
  131. NSArray *bulkSizes = @[@10, @50, @100, @500, @1000];
  132. for (NSNumber *sizeNumber in bulkSizes) {
  133. NSInteger size = [sizeNumber integerValue];
  134. // 清空数据
  135. [self.storage clearAll];
  136. // 测试批量插入性能
  137. NSDate *insertStart = [NSDate date];
  138. for (NSInteger i = 0; i < size; i++) {
  139. NSString *episodeId = [NSString stringWithFormat:@"bulk_ep_%ld", (long)i];
  140. [self.storage saveProgressWithEpisodeId:episodeId
  141. dramaId:@"bulk_drama"
  142. position:arc4random() % 120000
  143. duration:120000
  144. isCompleted:NO
  145. synced:NO
  146. completion:nil];
  147. }
  148. NSTimeInterval insertTime = [[NSDate date] timeIntervalSinceDate:insertStart];
  149. // 测试批量查询性能
  150. NSDate *queryStart = [NSDate date];
  151. [self.storage getProgressByDramaId:@"bulk_drama"];
  152. NSTimeInterval queryTime = [[NSDate date] timeIntervalSinceDate:queryStart];
  153. // 测试批量删除性能
  154. NSDate *deleteStart = [NSDate date];
  155. [self.storage deleteProgressByDramaId:@"bulk_drama"];
  156. NSTimeInterval deleteTime = [[NSDate date] timeIntervalSinceDate:deleteStart];
  157. NSLog(@"Bulk size: %ld", (long)size);
  158. NSLog(@"Insert time: %.3fms", insertTime * 1000);
  159. NSLog(@"Query time: %.3fms", queryTime * 1000);
  160. NSLog(@"Delete time: %.3fms", deleteTime * 1000);
  161. NSLog(@"---");
  162. }
  163. }
  164. - (void)testConcurrentOperationPerformance {
  165. NSInteger concurrentOperations = 50;
  166. NSDate *startTime = [NSDate date];
  167. // 模拟并发操作
  168. for (NSInteger i = 0; i < concurrentOperations; i++) {
  169. NSString *episodeId = [NSString stringWithFormat:@"concurrent_ep_%ld", (long)i];
  170. NSString *dramaId = [NSString stringWithFormat:@"concurrent_drama_%ld", (long)(i % 10)]; // 10个不同的剧
  171. [self.storage saveProgressWithEpisodeId:episodeId
  172. dramaId:dramaId
  173. position:arc4random() % 120000
  174. duration:120000
  175. isCompleted:NO
  176. synced:NO
  177. completion:nil];
  178. // 每隔几次操作就查询一次
  179. if (i % 5 == 0 && i > 0) {
  180. NSString *queryEpisodeId = [NSString stringWithFormat:@"concurrent_ep_%ld", (long)(i - 1)];
  181. [self.storage getProgressWithEpisodeId:queryEpisodeId];
  182. }
  183. }
  184. NSTimeInterval totalTime = [[NSDate date] timeIntervalSinceDate:startTime];
  185. NSLog(@"Concurrent operations (%ld): %.3fms", (long)concurrentOperations, totalTime * 1000);
  186. NSLog(@"Average per operation: %.3fms", (totalTime * 1000) / concurrentOperations);
  187. }
  188. #pragma mark - 内存使用测试
  189. - (void)testMemoryUsagePattern {
  190. // 获取初始内存使用情况
  191. struct mach_task_basic_info info;
  192. mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
  193. kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
  194. vm_size_t initialMemory = 0;
  195. if (kerr == KERN_SUCCESS) {
  196. initialMemory = info.resident_size;
  197. }
  198. NSLog(@"Initial memory usage: %.2fMB", initialMemory / 1024.0 / 1024.0);
  199. // 执行大量操作
  200. for (int i = 0; i < 1000; i++) {
  201. NSString *episodeId = [NSString stringWithFormat:@"memory_ep_%d", i];
  202. NSString *dramaId = [NSString stringWithFormat:@"memory_drama_%d", i % 20];
  203. [self.storage saveProgressWithEpisodeId:episodeId
  204. dramaId:dramaId
  205. position:arc4random() % 120000
  206. duration:120000
  207. isCompleted:NO
  208. synced:NO
  209. completion:nil];
  210. // 每100次操作检查一次内存
  211. if (i % 100 == 0) {
  212. kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
  213. if (kerr == KERN_SUCCESS) {
  214. NSLog(@"Memory after %d operations: %.2fMB", i, info.resident_size / 1024.0 / 1024.0);
  215. }
  216. }
  217. }
  218. // 执行查询操作
  219. for (int i = 0; i < 100; i++) {
  220. NSString *dramaId = [NSString stringWithFormat:@"memory_drama_%d", i % 20];
  221. [self.storage getProgressByDramaId:dramaId];
  222. }
  223. // 记录最终内存
  224. kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
  225. if (kerr == KERN_SUCCESS) {
  226. vm_size_t finalMemory = info.resident_size;
  227. NSLog(@"Final memory usage: %.2fMB", finalMemory / 1024.0 / 1024.0);
  228. NSLog(@"Memory increase: %.2fMB", (finalMemory - initialMemory) / 1024.0 / 1024.0);
  229. }
  230. }
  231. #pragma mark - 数据库增长性能测试
  232. - (void)testDatabaseGrowthPerformance {
  233. NSArray *growthSteps = @[@100, @500, @1000, @2000, @5000];
  234. for (NSNumber *totalRecordsNumber in growthSteps) {
  235. NSInteger totalRecords = [totalRecordsNumber integerValue];
  236. // 清空并重新填充到指定数量
  237. [self.storage clearAll];
  238. NSDate *populateStart = [NSDate date];
  239. for (NSInteger i = 0; i < totalRecords; i++) {
  240. NSString *episodeId = [NSString stringWithFormat:@"growth_ep_%ld", (long)i];
  241. NSString *dramaId = [NSString stringWithFormat:@"growth_drama_%ld", (long)(i % 100)];
  242. [self.storage saveProgressWithEpisodeId:episodeId
  243. dramaId:dramaId
  244. position:arc4random() % 120000
  245. duration:120000
  246. isCompleted:NO
  247. synced:NO
  248. completion:nil];
  249. }
  250. NSTimeInterval populateTime = [[NSDate date] timeIntervalSinceDate:populateStart];
  251. // 测试在不同数据量下的查询性能
  252. NSDate *queryStart = [NSDate date];
  253. for (int i = 0; i < 50; i++) {
  254. NSString *randomEpisodeId = [NSString stringWithFormat:@"growth_ep_%d", arc4random() % (int)totalRecords];
  255. [self.storage getProgressWithEpisodeId:randomEpisodeId];
  256. }
  257. NSTimeInterval queryTime = [[NSDate date] timeIntervalSinceDate:queryStart];
  258. NSDate *unsyncedQueryStart = [NSDate date];
  259. [self.storage getUnsyncedProgresses];
  260. NSTimeInterval unsyncedQueryTime = [[NSDate date] timeIntervalSinceDate:unsyncedQueryStart];
  261. NSLog(@"Records: %ld", (long)totalRecords);
  262. NSLog(@"Populate time: %.3fms", populateTime * 1000);
  263. NSLog(@"Query time (50 queries): %.3fms", queryTime * 1000);
  264. NSLog(@"Unsynced query time: %.3fms", unsyncedQueryTime * 1000);
  265. NSLog(@"---");
  266. }
  267. }
  268. #pragma mark - 格式化工具大数据集性能测试
  269. - (void)testFormatterPerformanceWithLargeDataset {
  270. NSMutableArray *largeDataset = [NSMutableArray array];
  271. for (int i = 0; i < 10000; i++) {
  272. [largeDataset addObject:@(arc4random() % 10000000000LL)]; // 0到100亿
  273. }
  274. NSDate *formatStart = [NSDate date];
  275. for (NSNumber *number in largeDataset) {
  276. [JXCountFormatter formatCount:[number longLongValue]];
  277. }
  278. NSTimeInterval formatTime = [[NSDate date] timeIntervalSinceDate:formatStart];
  279. NSDate *specificFormatStart = [NSDate date];
  280. for (NSNumber *number in largeDataset) {
  281. long long numberValue = [number longLongValue];
  282. [JXCountFormatter formatLikeCount:numberValue];
  283. [JXCountFormatter formatPlayCount:numberValue];
  284. }
  285. NSTimeInterval specificFormatTime = [[NSDate date] timeIntervalSinceDate:specificFormatStart];
  286. NSLog(@"Format 10k numbers: %.3fms", formatTime * 1000);
  287. NSLog(@"Specific format 20k calls: %.3fms", specificFormatTime * 1000);
  288. NSLog(@"Average format time: %.6fms per number", (formatTime * 1000) / largeDataset.count);
  289. }
  290. #pragma mark - 压力测试
  291. - (void)testStressTestContinuousOperations {
  292. NSInteger operationCount = 1000;
  293. NSDate *startTime = [NSDate date];
  294. for (NSInteger i = 0; i < operationCount; i++) {
  295. // 随机操作类型
  296. NSInteger operationType = arc4random() % 4;
  297. NSString *episodeId = [NSString stringWithFormat:@"stress_ep_%ld", (long)(arc4random() % 100)];
  298. NSString *dramaId = [NSString stringWithFormat:@"stress_drama_%ld", (long)(arc4random() % 10)];
  299. switch (operationType) {
  300. case 0: // 保存进度
  301. [self.storage saveProgressWithEpisodeId:episodeId
  302. dramaId:dramaId
  303. position:arc4random() % 120000
  304. duration:120000
  305. isCompleted:NO
  306. synced:NO
  307. completion:nil];
  308. break;
  309. case 1: // 查询单个进度
  310. [self.storage getProgressWithEpisodeId:episodeId];
  311. break;
  312. case 2: // 查询剧进度
  313. [self.storage getProgressByDramaId:dramaId];
  314. break;
  315. case 3: // 查询未同步进度
  316. [self.storage getUnsyncedProgresses];
  317. break;
  318. }
  319. }
  320. NSTimeInterval totalTime = [[NSDate date] timeIntervalSinceDate:startTime];
  321. NSLog(@"Stress test (%ld operations): %.3fms", (long)operationCount, totalTime * 1000);
  322. NSLog(@"Average per operation: %.6fms", (totalTime * 1000) / operationCount);
  323. }
  324. @end