Bug 251261

Summary: Large allocations in a tight loop perform poorly when using the JavaScriptCore C and Objective-C APIs
Product: WebKit Reporter: Kasper Isager Dalsgarð <kasperisager>
Component: JavaScriptCoreAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: ap, cdumez, mark.lam, webkit-bug-importer, ysuzuki
Priority: P2 Keywords: InRadar
Version: WebKit Local Build   
Hardware: Mac (Apple Silicon)   
OS: macOS 13   
Attachments:
Description Flags
Output generated by JSC_dumpDisassembly
none
CPU profile of `JavaScriptCore.framework/Versions/Current/Helpers/jsc`
none
CPU profile of `a.out`
none
GC logs for `JavaScriptCore.framework/Versions/Current/Helpers/jsc`
none
GC logs for `a.out` none

Description Kasper Isager Dalsgarð 2023-01-27 04:29:14 PST
Consider the following C and Objective-C programs that perform 64 KiB allocations in a tight loop:

```
#include <JavaScriptCore/JavaScriptCore.h>

int
main () {
  JSContextRef context = JSGlobalContextCreate(NULL);

  JSStringRef source = JSStringCreateWithUTF8CString(
    "for (let i = 0; i < 1e6; i++) new Uint8Array(1024 * 64)"
  );

  JSEvaluateScript(context, source, NULL, NULL, 1, NULL);
}

```

```
#include <JavaScriptCore/JavaScriptCore.h>

int
main () {
  JSContext *context = [[JSContext alloc] init];

  [context evaluateScript:@"for (let i = 0; i < 1e6; i++) new Uint8Array(1024 * 64)"];
}
```

When running these on my machine, I'm observing an 8x slowdown compared to running the same allocation loop in either Safari or using the jsc helper from the builtin JavaScriptCore framework (/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Helpers/jsc) and I cannot seem to figure out why. Both programs were compiled with clang using -O3.
Comment 1 Alexey Proskuryakov 2023-01-28 16:55:50 PST
Does your test program allow JIT? https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit
Comment 2 Kasper Isager Dalsgarð 2023-01-29 23:51:17 PST
I think so, yes, but I'm unsure how to verify that's it's actually working:

```
$ codesign --display --entitlements - a.out
Executable=<cwd>/a.out
[Dict]
	[Key] com.apple.security.cs.allow-jit
	[Value]
		[Bool] true
```

Code signed with the following command:

```
$ codesign --force --options runtime --sign <key> --entitlements entitlements.plist a.out
```

I don't know if it provides any clues, but reducing the size of each allocation to just 1 KiB instead of 64 KiB makes my test program perform similar to Safari and jsc. What kind of optimisations would the JIT be able to do for larger allocations?
Comment 3 Alexey Proskuryakov 2023-01-30 08:33:59 PST
Not sure, CC'ing some folks who would know. 

FWIW, the jsc binary on macOS has more JIT related entitlements, but others don't seem to be documented.
Comment 4 Kasper Isager Dalsgarð 2023-01-30 12:11:50 PST
Tried matching the jsc entitlements with the exception of com.apple.private.verified-jit, but no dice I'm afraid:

```
$ codesign --display --entitlements - a.out
Executable=<cwd>/a.out
[Dict]
	[Key] com.apple.security.cs.allow-jit
	[Value]
		[Bool] true
	[Key] com.apple.security.cs.jit-write-allowlist
	[Value]
		[Bool] true
	[Key] com.apple.security.cs.single-jit
	[Value]
		[Bool] true
```
Comment 5 Radar WebKit Bug Importer 2023-02-03 04:30:19 PST
<rdar://problem/105001996>
Comment 6 Yusuke Suzuki 2023-02-15 17:02:51 PST
Can you run this with `JSC_dumpDisassembly=1` environment variable?
If JIT code is generated from that, then JIT is enabled. If not, JIT is not enabled.
Comment 7 Kasper Isager Dalsgarð 2023-02-17 00:40:49 PST
Created attachment 465047 [details]
Output generated by JSC_dumpDisassembly
Comment 8 Kasper Isager Dalsgarð 2023-02-17 00:41:55 PST
I've uploaded an attachment with the generated output, let me know if there's anything else I can provide!
Comment 9 Kasper Isager Dalsgarð 2023-05-23 00:14:03 PDT
Do you need anything more from me on this?
Comment 10 Mark Lam 2023-05-23 09:46:26 PDT
Hi Kasper, your dump shows that you are getting JIT support.  So, this is not an issue with the JIT being disabled.

Next steps:

1. How are you measuring the 8x slowdown?  Your description below didn't describe this.  Please describe this so that we can make sure that you're comparing equivalent things.

2. My gut feeling is that there might be GC activity at play.  Try running your executable and jsc with JSC_logGC=1, and see if there's a difference in GC activity.

3. Run Instruments profiler and collect CPU profiles for runs with your executable and with jsc.  Then compare to see if there's a difference in the profiles.

Based on the data you get from those, we may be able to give you more advice.  Thanks.
Comment 11 Kasper Isager Dalsgarð 2023-05-24 00:20:00 PDT
Created attachment 466474 [details]
CPU profile of `JavaScriptCore.framework/Versions/Current/Helpers/jsc`
Comment 12 Kasper Isager Dalsgarð 2023-05-24 00:20:48 PDT
Created attachment 466475 [details]
CPU profile of `a.out`
Comment 13 Kasper Isager Dalsgarð 2023-05-24 00:21:25 PDT
Created attachment 466476 [details]
GC logs for `JavaScriptCore.framework/Versions/Current/Helpers/jsc`
Comment 14 Kasper Isager Dalsgarð 2023-05-24 00:22:45 PDT
Created attachment 466477 [details]
GC logs for `a.out`
Comment 15 Kasper Isager Dalsgarð 2023-05-24 00:33:23 PDT
Thanks for detailing the additional steps!

1. I've run both my compiled programs (a.out) and the jsc helper (/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Helpers/jsc) through `time` and the slowdown I reported was based on those timings. For the jsc helper, I stuffed the loop in a JavaScript file and passed that to jsc.

2. I've attached the GC logs for both the jsc helper and one of my programs. I think it's safe to say that the GC is on overdrive in my programs; I'm counting 215,577 occurrences of "GC END" for my programs, but only 5,874 occurrences in the case of jsc.

3. I've attached the CPU profiles for both the jsc helper and one of my programs. They look very similar to me, except for the total durations, and I'm unsure where to look specifically for GC activity.
Comment 16 Kasper Isager Dalsgarð 2023-08-27 07:32:57 PDT
Is there anything else I can do to help identify the cause of this?
Comment 17 Kasper Isager Dalsgarð 2023-09-27 04:26:12 PDT
This went away after upgrading to macOS 14 so I assume whatever caused this was fixed. Marking as resolved.