Skip to content

Commit

Permalink
KSCrashReport buffered output
Browse files Browse the repository at this point in the history
  • Loading branch information
nickdowell committed Jan 12, 2022
1 parent 7023d51 commit f4a0ede
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 24 deletions.
18 changes: 18 additions & 0 deletions Bugsnag.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,13 @@
01C17AE72542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */; };
01C17AE82542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */; };
01C17AE92542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */; };
01CB95BF278F0C830077744A /* BSG_KSFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CB95BD278F0C830077744A /* BSG_KSFile.h */; };
01CB95C0278F0C830077744A /* BSG_KSFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CB95BD278F0C830077744A /* BSG_KSFile.h */; };
01CB95C1278F0C830077744A /* BSG_KSFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CB95BD278F0C830077744A /* BSG_KSFile.h */; };
01CB95C2278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; };
01CB95C3278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; };
01CB95C4278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; };
01CB95C5278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; };
01CCAEEA25D414D60057268D /* BugsnagLastRunInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
01CCAEEB25D414D60057268D /* BugsnagLastRunInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
01CCAEEC25D414D60057268D /* BugsnagLastRunInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -1385,6 +1392,8 @@
01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSCrashReportWriterTests.m; sourceTree = "<group>"; };
01C2769B2601F44D006901EA /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
01C2769C2601F455006901EA /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = "<group>"; };
01CB95BD278F0C830077744A /* BSG_KSFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSG_KSFile.h; sourceTree = "<group>"; };
01CB95BE278F0C830077744A /* BSG_KSFile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = BSG_KSFile.c; sourceTree = "<group>"; };
01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagLastRunInfo.h; sourceTree = "<group>"; };
01CCAEE925D414D60057268D /* BugsnagLastRunInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BugsnagLastRunInfo.m; sourceTree = "<group>"; };
01CCAEFF25D4151C0057268D /* BugsnagLastRunInfo+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagLastRunInfo+Private.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1628,6 +1637,8 @@
008969292486DAD000DC48C2 /* BSG_KSCrashState.m */,
0089692B2486DAD000DC48C2 /* BSG_KSCrashType.c */,
008969482486DAD000DC48C2 /* BSG_KSCrashType.h */,
01CB95BE278F0C830077744A /* BSG_KSFile.c */,
01CB95BD278F0C830077744A /* BSG_KSFile.h */,
0089692F2486DAD000DC48C2 /* BSG_KSSystemInfo.h */,
0089694C2486DAD000DC48C2 /* BSG_KSSystemInfo.m */,
008969312486DAD000DC48C2 /* BSG_KSSystemInfoC.h */,
Expand Down Expand Up @@ -2146,6 +2157,7 @@
010FF28425ED2A8D00E4F2B0 /* BSGAppHangDetector.h in Headers */,
008967F42486DA4500DC48C2 /* BSGSessionUploader.h in Headers */,
0126DF1B257A92860031A70C /* BugsnagSession+Private.h in Headers */,
01CB95BF278F0C830077744A /* BSG_KSFile.h in Headers */,
008969E12486DAD100DC48C2 /* BSG_KSSystemInfo.h in Headers */,
00896A0E2486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */,
008969D22486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */,
Expand Down Expand Up @@ -2252,6 +2264,7 @@
008967F52486DA4500DC48C2 /* BSGSessionUploader.h in Headers */,
010FF28525ED2A8D00E4F2B0 /* BSGAppHangDetector.h in Headers */,
008969E22486DAD100DC48C2 /* BSG_KSSystemInfo.h in Headers */,
01CB95C0278F0C830077744A /* BSG_KSFile.h in Headers */,
0126DF1C257A92860031A70C /* BugsnagSession+Private.h in Headers */,
00896A0F2486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */,
008969D32486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */,
Expand Down Expand Up @@ -2358,6 +2371,7 @@
008967F62486DA4500DC48C2 /* BSGSessionUploader.h in Headers */,
010FF28625ED2A8D00E4F2B0 /* BSGAppHangDetector.h in Headers */,
008969E32486DAD100DC48C2 /* BSG_KSSystemInfo.h in Headers */,
01CB95C1278F0C830077744A /* BSG_KSFile.h in Headers */,
0126DF1D257A92860031A70C /* BugsnagSession+Private.h in Headers */,
00896A102486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */,
008969D42486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */,
Expand Down Expand Up @@ -2741,6 +2755,7 @@
01840B7225DC26E200F95648 /* BSGEventUploader.m in Sources */,
008968C32486DA9600DC48C2 /* BugsnagUser.m in Sources */,
CBAB4DD82510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */,
01CB95C2278F0C830077744A /* BSG_KSFile.c in Sources */,
008968A72486DA9600DC48C2 /* BugsnagSession.m in Sources */,
0089683A2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */,
013D9CD426C5262F0077F0AD /* UISceneStub.m in Sources */,
Expand Down Expand Up @@ -2898,6 +2913,7 @@
008968BA2486DA9600DC48C2 /* BugsnagStacktrace.m in Sources */,
00896A152486DAD100DC48C2 /* BSG_KSCrashSentry_Signal.c in Sources */,
01468F5625876DC1002B0519 /* BSGNotificationBreadcrumbs.m in Sources */,
01CB95C3278F0C830077744A /* BSG_KSFile.c in Sources */,
008967BF2486DA1900DC48C2 /* BugsnagClient.m in Sources */,
008968962486DA9600DC48C2 /* BugsnagHandledState.m in Sources */,
008969C42486DAD100DC48C2 /* BSG_KSObjC.c in Sources */,
Expand Down Expand Up @@ -3088,6 +3104,7 @@
01840B7425DC26E200F95648 /* BSGEventUploader.m in Sources */,
008968C52486DA9600DC48C2 /* BugsnagUser.m in Sources */,
CBAB4DDA2510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */,
01CB95C4278F0C830077744A /* BSG_KSFile.c in Sources */,
008968A92486DA9600DC48C2 /* BugsnagSession.m in Sources */,
0089683C2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */,
013D9CD626C5262F0077F0AD /* UISceneStub.m in Sources */,
Expand Down Expand Up @@ -3261,6 +3278,7 @@
008967DD2486DA2D00DC48C2 /* BugsnagConfiguration.m in Sources */,
008968E42486DAA700DC48C2 /* BugsnagPluginClient.m in Sources */,
01840B7525DC26E200F95648 /* BSGEventUploader.m in Sources */,
01CB95C5278F0C830077744A /* BSG_KSFile.c in Sources */,
008968BC2486DA9600DC48C2 /* BugsnagStacktrace.m in Sources */,
008968242486DA5600DC48C2 /* BugsnagKeys.m in Sources */,
008967B72486D9D800DC48C2 /* BugsnagBreadcrumbs.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.065700</real>
<real>0.034600</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.468000</real>
<real>0.195000</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.091900</real>
<real>0.042200</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
Expand Down
22 changes: 16 additions & 6 deletions Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "BSG_KSBacktrace_Private.h"
#include "BSG_KSCrashReportFields.h"
#include "BSG_KSCrashReportVersion.h"
#include "BSG_KSFile.h"
#include "BSG_KSFileUtils.h"
#include "BSG_KSJSONCodec.h"
#include "BSG_KSMach.h"
Expand Down Expand Up @@ -308,8 +309,7 @@ void bsg_kscrw_i_endContainer(const BSG_KSCrashReportWriter *const writer) {

int bsg_kscrw_i_addJSONData(const char *const data, const size_t length,
void *const userData) {
const int fd = *((int *)userData);
const bool success = bsg_ksfuwriteBytesToFD(fd, data, (ssize_t)length);
bool success = BSG_KSFileWrite(userData, data, length);
return success ? BSG_KSJSON_OK : BSG_KSJSON_ERROR_CANNOT_ADD_DATA;
}

Expand Down Expand Up @@ -1502,14 +1502,18 @@ void bsg_kscrashreport_writeMinimalReport(

bsg_kscrw_i_updateStackOverflowStatus(crashContext);

BSG_KSFile file;
char buffer[512];
BSG_KSFileInit(&file, fd, buffer, sizeof(buffer) / sizeof(*buffer));

BSG_KSJSONEncodeContext jsonContext;
jsonContext.userData = &fd;
jsonContext.userData = &file;
BSG_KSCrashReportWriter concreteWriter;
BSG_KSCrashReportWriter *writer = &concreteWriter;
bsg_kscrw_i_prepareReportWriter(writer, &jsonContext);

bsg_ksjsonbeginEncode(bsg_getJsonContext(writer), false,
bsg_kscrw_i_addJSONData, &fd);
bsg_kscrw_i_addJSONData, &file);

writer->beginObject(writer, BSG_KSCrashField_Report);
{
Expand Down Expand Up @@ -1541,6 +1545,7 @@ void bsg_kscrashreport_writeMinimalReport(

bsg_ksjsonendEncode(bsg_getJsonContext(writer));

BSG_KSFileFlush(&file);
close(fd);
}

Expand All @@ -1557,14 +1562,18 @@ void bsg_kscrashreport_writeStandardReport(

bsg_kscrw_i_updateStackOverflowStatus(crashContext);

BSG_KSFile file;
char buffer[4096];
BSG_KSFileInit(&file, fd, buffer, sizeof(buffer) / sizeof(*buffer));

BSG_KSJSONEncodeContext jsonContext;
jsonContext.userData = &fd;
jsonContext.userData = &file;
BSG_KSCrashReportWriter concreteWriter;
BSG_KSCrashReportWriter *writer = &concreteWriter;
bsg_kscrw_i_prepareReportWriter(writer, &jsonContext);

bsg_ksjsonbeginEncode(bsg_getJsonContext(writer), false,
bsg_kscrw_i_addJSONData, &fd);
bsg_kscrw_i_addJSONData, &file);

writer->beginObject(writer, BSG_KSCrashField_Report);
{
Expand All @@ -1588,6 +1597,7 @@ void bsg_kscrashreport_writeStandardReport(

bsg_ksjsonendEncode(bsg_getJsonContext(writer));

BSG_KSFileFlush(&file);
close(fd);
}

Expand Down
62 changes: 62 additions & 0 deletions Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// BSG_KSFile.c
// Bugsnag
//
// Created by Nick Dowell on 12/01/2022.
// Copyright © 2022 Bugsnag Inc. All rights reserved.
//

#include "BSG_KSFile.h"

#include "BSG_KSFileUtils.h"

#include <string.h>
#include <sys/param.h>

static inline bool bsg_write(const int fd, const char *bytes, size_t length) {
return bsg_ksfuwriteBytesToFD(fd, bytes, (ssize_t)length);
}

void BSG_KSFileInit(BSG_KSFile *file, int fd, char *buffer, size_t length) {
file->fd = fd;
file->buffer = buffer;
file->bufferSize = length;
file->bufferUsed = 0;
}

bool BSG_KSFileWrite(BSG_KSFile *file, const char *data, size_t length) {
const size_t bytesCopied = MIN(file->bufferSize - file->bufferUsed, length);
memcpy(file->buffer + file->bufferUsed, data, bytesCopied);
file->bufferUsed += bytesCopied;
data += bytesCopied;
length -= bytesCopied;

if (file->bufferUsed == file->bufferSize) {
if (!BSG_KSFileFlush(file)) {
return false;
}
}

if (!length) {
return true;
}

if (length >= file->bufferSize) {
return bsg_write(file->fd, data, length);
}

memcpy(file->buffer, data, length);
file->bufferUsed = length;
return true;
}

bool BSG_KSFileFlush(BSG_KSFile *file) {
if (!file->bufferUsed) {
return 0;
}
if (!bsg_write(file->fd, file->buffer, file->bufferUsed)) {
return false;
}
file->bufferUsed = 0;
return true;
}
25 changes: 25 additions & 0 deletions Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// BSG_KSFile.h
// Bugsnag
//
// Created by Nick Dowell on 12/01/2022.
// Copyright © 2022 Bugsnag Inc. All rights reserved.
//

#pragma once

#include <stdbool.h>
#include <stddef.h>

typedef struct {
int fd;
char *buffer;
size_t bufferSize;
size_t bufferUsed;
} BSG_KSFile;

void BSG_KSFileInit(BSG_KSFile *file, int fd, char *buffer, size_t length);

bool BSG_KSFileWrite(BSG_KSFile *file, const char *data, size_t length);

bool BSG_KSFileFlush(BSG_KSFile *file);
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

## TBD

### Bug fixes

* Improve crash report writing performance with buffered output.
[#1281](https://github.com/bugsnag/bugsnag-cocoa/pull/1281)

## 6.16.0 (2022-01-12)

### Enhancements
Expand Down
32 changes: 17 additions & 15 deletions Tests/KSCrashTests/BSG_KSCrashReportTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ @interface BSG_KSCrashReportTests : XCTestCase
@implementation BSG_KSCrashReportTests

- (void)testBinaryImages {
NSString *directory = NSTemporaryDirectory();
NSString *crashReportFilePath = [directory stringByAppendingPathComponent:@"crash_report"];
NSString *recrashReportFilePath = [directory stringByAppendingPathComponent:@"recrash_report"];
NSString *stateFilePath = [directory stringByAppendingPathComponent:@"kscrash_state"];
NSString *crashReportFilePath = [self temporaryFile:@"crash_report.json"];
NSString *recrashReportFilePath = [self temporaryFile:@"recrash_report"];
NSString *stateFilePath = [self temporaryFile:@"kscrash_state"];
NSString *crashID = [[NSUUID UUID] UUIDString];

bsg_kscrash_init();
Expand Down Expand Up @@ -62,17 +61,12 @@ - (void)testBinaryImages {
[backtraceImageAddrs removeObject:[NSNull null]];

XCTAssertEqualObjects(binaryImageAddrs, backtraceImageAddrs);

[[NSFileManager defaultManager] removeItemAtPath:crashReportFilePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:recrashReportFilePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:stateFilePath error:nil];
}

- (void)testWriteStandardReportPerformance {
NSString *directory = NSTemporaryDirectory();
NSString *crashReportFilePath = [directory stringByAppendingPathComponent:@"crash_report"];
NSString *recrashReportFilePath = [directory stringByAppendingPathComponent:@"recrash_report"];
NSString *stateFilePath = [directory stringByAppendingPathComponent:@"kscrash_state"];
NSString *crashReportFilePath = [self temporaryFile:@"crash_report"];
NSString *recrashReportFilePath = [self temporaryFile:@"recrash_report"];
NSString *stateFilePath = [self temporaryFile:@"kscrash_state"];
NSString *crashID = [[NSUUID UUID] UUIDString];

bsg_kscrash_init();
Expand Down Expand Up @@ -111,11 +105,19 @@ - (void)testWriteStandardReportPerformance {
}
[self stopMeasuring];

NSDictionary *report = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:crashReportFilePath] options:0 error:nil];
XCTAssert([report isKindOfClass:[NSDictionary class]], @"%@", report);
[[NSFileManager defaultManager] removeItemAtPath:crashReportFilePath error:nil];
}];

[[NSFileManager defaultManager] removeItemAtPath:recrashReportFilePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:stateFilePath error:nil];
}

- (NSString *)temporaryFile:(NSString *)fileName {
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
[self addTeardownBlock:^{
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}];
return path;
}

@end

0 comments on commit f4a0ede

Please sign in to comment.