1/* 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8 9#import "ResourceTestCase.h" 10 11#import <executorch/examples/models/llama/runner/runner.h> 12 13using namespace ::executorch::extension; 14using namespace ::executorch::runtime; 15 16@interface TokensPerSecondMetric : NSObject<XCTMetric> 17 18@property(nonatomic, assign) NSUInteger tokenCount; 19 20@end 21 22@implementation TokensPerSecondMetric 23 24- (id)copyWithZone:(NSZone *)zone { 25 TokensPerSecondMetric *copy = [[[self class] allocWithZone:zone] init]; 26 copy.tokenCount = self.tokenCount; 27 return copy; 28} 29 30- (NSArray<XCTPerformanceMeasurement *> *) 31 reportMeasurementsFromStartTime: 32 (XCTPerformanceMeasurementTimestamp *)startTime 33 toEndTime: 34 (XCTPerformanceMeasurementTimestamp *)endTime 35 error:(NSError **)error { 36 double elapsedTime = 37 (endTime.absoluteTimeNanoSeconds - startTime.absoluteTimeNanoSeconds) / 38 (double)NSEC_PER_SEC; 39 return @[ [[XCTPerformanceMeasurement alloc] 40 initWithIdentifier:NSStringFromClass([self class]) 41 displayName:@"Tokens Per Second" 42 doubleValue:(self.tokenCount / elapsedTime) 43 unitSymbol:@"t/s"] ]; 44} 45 46@end 47 48@interface LLaMATests : ResourceTestCase 49@end 50 51@implementation LLaMATests 52 53+ (NSArray<NSString *> *)directories { 54 return @[ 55 @"Resources", 56 @"aatp/data", // AWS Farm devices look for resources here. 57 ]; 58} 59 60+ (NSDictionary<NSString *, BOOL (^)(NSString *)> *)predicates { 61 return @{ 62 @"model" : ^BOOL(NSString *filename){ 63 return [filename hasSuffix:@".pte"] && [filename containsString:@"llama"]; 64 }, 65 @"tokenizer" : ^BOOL(NSString *filename) { 66 return [filename isEqual:@"tokenizer.bin"]; 67 }, 68 }; 69} 70 71+ (NSDictionary<NSString *, void (^)(XCTestCase *)> *)dynamicTestsForResources: 72 (NSDictionary<NSString *, NSString *> *)resources { 73 NSString *modelPath = resources[@"model"]; 74 NSString *tokenizerPath = resources[@"tokenizer"]; 75 return @{ 76 @"generate" : ^(XCTestCase *testCase){ 77 auto __block runner = std::make_unique<example::Runner>( 78 modelPath.UTF8String, tokenizerPath.UTF8String); 79 const auto status = runner->load(); 80 if (status != Error::Ok) { 81 XCTFail("Load failed with error %i", status); 82 return; 83 } 84 TokensPerSecondMetric *tokensPerSecondMetric = [TokensPerSecondMetric new]; 85 [testCase measureWithMetrics:@[ tokensPerSecondMetric, [XCTMemoryMetric new] ] 86 block:^{ 87 tokensPerSecondMetric.tokenCount = 0; 88 const auto status = runner->generate( 89 "Once upon a time", 90 128, 91 [=](const std::string &token) { 92 tokensPerSecondMetric.tokenCount++; 93 }, 94 nullptr, 95 false); 96 XCTAssertEqual(status, Error::Ok); 97 }]; 98 }, 99 }; 100} 101 102@end 103