Add systrace controls window

Summary:Add a couple functions to show and hide a small window with buttons to start/stop
systrace and reload the current bridge. After stop profiling, the results will
be saved to a temporary file, and a share sheet will show up with the file attached
so that you can send it to your computer whatever way is more convenient.

Depends on D2700069

Reviewed By: jspahrsummers

Differential Revision: D2811560

fb-gh-sync-id: 5e91ece3a7ea748d4cb5fbc612a9b76ab80fc8f3
shipit-source-id: 5e91ece3a7ea748d4cb5fbc612a9b76ab80fc8f3
This commit is contained in:
Tadeu Zagallo 2016-03-11 06:20:24 -08:00 committed by Facebook Github Bot 0
parent fd816b1349
commit de53ef1c9a
2 changed files with 108 additions and 0 deletions

View File

@ -185,6 +185,12 @@ typedef struct {
RCT_EXTERN void RCTProfileRegisterCallbacks(RCTProfileCallbacks *);
/**
* Systrace control window
*/
RCT_EXTERN void RCTProfileShowControls(void);
RCT_EXTERN void RCTProfileHideControls(void);
#else
#define RCTProfileBeginFlowEvent()
@ -215,4 +221,7 @@ RCT_EXTERN void RCTProfileRegisterCallbacks(RCTProfileCallbacks *);
#define RCTProfileSendResult(...)
#define RCTProfileShowControls(...)
#define RCTProfileHideControls(...)
#endif

View File

@ -50,6 +50,8 @@ static NSMutableDictionary *RCTProfileOngoingEvents;
static NSTimeInterval RCTProfileStartTime;
static NSUInteger RCTProfileEventID = 0;
static CADisplayLink *RCTProfileDisplayLink;
static __weak RCTBridge *_RCTProfilingBridge;
static UIWindow *RCTProfileControlsWindow;
#pragma mark - Macros
@ -97,6 +99,11 @@ void RCTProfileRegisterCallbacks(RCTProfileCallbacks *cb)
#pragma mark - Private Helpers
static RCTBridge *RCTProfilingBridge(void)
{
return _RCTProfilingBridge ?: [RCTBridge currentBridge];
}
static NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
{
return @((timestamp - RCTProfileStartTime) * 1e6);
@ -288,6 +295,8 @@ UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag)
void RCTProfileHookModules(RCTBridge *bridge)
{
_RCTProfilingBridge = bridge;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
if (RCTProfileTrampoline == NULL) {
@ -324,6 +333,8 @@ static void RCTProfileUnhookInstance(id instance)
void RCTProfileUnhookModules(RCTBridge *bridge)
{
_RCTProfilingBridge = nil;
dispatch_group_enter(RCTProfileGetUnhookGroup());
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
@ -351,6 +362,54 @@ void RCTProfileUnhookModules(RCTBridge *bridge)
RCTProfileImmediateEvent(0, @"VSYNC", displayLink.timestamp, 'g');
}
+ (void)reload
{
[RCTProfilingBridge() reload];
}
+ (void)toggle:(UIButton *)target
{
BOOL isProfiling = RCTProfileIsProfiling();
// Start and Stop are switched here, since we're going to toggle isProfiling
[target setTitle:isProfiling ? @"Start" : @"Stop"
forState:UIControlStateNormal];
if (isProfiling) {
RCTProfileEnd(RCTProfilingBridge(), ^(NSString *result) {
NSString *outFile = [NSTemporaryDirectory() stringByAppendingString:@"tmp_trace.json"];
[result writeToFile:outFile
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[[NSURL fileURLWithPath:outFile]]
applicationActivities:nil];
activityViewController.completionHandler = ^(__unused NSString *activityType, __unused BOOL completed) {
RCTProfileControlsWindow.hidden = NO;
};
RCTProfileControlsWindow.hidden = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:activityViewController
animated:YES
completion:nil];
});
});
} else {
RCTProfileInit(RCTProfilingBridge());
}
}
+ (void)drag:(UIPanGestureRecognizer *)gestureRecognizer
{
CGPoint translation = [gestureRecognizer translationInView:RCTProfileControlsWindow];
RCTProfileControlsWindow.center = CGPointMake(
RCTProfileControlsWindow.center.x + translation.x,
RCTProfileControlsWindow.center.y + translation.y
);
[gestureRecognizer setTranslation:CGPointMake(0, 0)
inView:RCTProfileControlsWindow];
}
@end
#pragma mark - Public Functions
@ -713,4 +772,44 @@ void RCTProfileSendResult(RCTBridge *bridge, NSString *route, NSData *data)
[task resume];
}
void RCTProfileShowControls(void)
{
static const CGFloat height = 30;
static const CGFloat width = 60;
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(20, 80, width * 2, height)];
window.windowLevel = UIWindowLevelAlert + 1000;
window.hidden = NO;
window.backgroundColor = [UIColor lightGrayColor];
window.layer.borderColor = [UIColor grayColor].CGColor;
window.layer.borderWidth = 1;
window.alpha = 0.8;
UIButton *startOrStop = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, width, height)];
[startOrStop setTitle:RCTProfileIsProfiling() ? @"Stop" : @"Start"
forState:UIControlStateNormal];
[startOrStop addTarget:[RCTProfile class] action:@selector(toggle:) forControlEvents:UIControlEventTouchUpInside];
startOrStop.titleLabel.font = [UIFont systemFontOfSize:12];
UIButton *reload = [[UIButton alloc] initWithFrame:CGRectMake(width, 0, width, height)];
[reload setTitle:@"Reload" forState:UIControlStateNormal];
[reload addTarget:[RCTProfile class] action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
reload.titleLabel.font = [UIFont systemFontOfSize:12];
[window addSubview:startOrStop];
[window addSubview:reload];
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:[RCTProfile class]
action:@selector(drag:)];
[window addGestureRecognizer:gestureRecognizer];
RCTProfileControlsWindow = window;
}
void RCTProfileHideControls(void)
{
RCTProfileControlsWindow.hidden = YES;
RCTProfileControlsWindow = nil;
}
#endif