Bug 237183 - [Cocoa] Allow logging to be configured by NSDefaults (without regressing launch time)
Summary: [Cocoa] Allow logging to be configured by NSDefaults (without regressing laun...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Jer Noble
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2022-02-24 22:23 PST by Jer Noble
Modified: 2022-03-01 10:14 PST (History)
2 users (show)

See Also:


Attachments
Patch (12.92 KB, patch)
2022-02-24 23:39 PST, Jer Noble
no flags Details | Formatted Diff | Diff
Patch (14.12 KB, patch)
2022-02-25 08:27 PST, Jer Noble
ews-feeder: commit-queue-
Details | Formatted Diff | Diff
Patch (17.24 KB, patch)
2022-02-25 08:32 PST, Jer Noble
no flags Details | Formatted Diff | Diff
Patch (17.27 KB, patch)
2022-02-26 17:18 PST, Jer Noble
no flags Details | Formatted Diff | Diff
Patch (17.33 KB, patch)
2022-02-27 06:29 PST, Jer Noble
no flags Details | Formatted Diff | Diff
Patch (17.93 KB, patch)
2022-02-28 09:20 PST, Jer Noble
ews-feeder: commit-queue-
Details | Formatted Diff | Diff
Patch (18.01 KB, patch)
2022-02-28 09:50 PST, Jer Noble
no flags Details | Formatted Diff | Diff
Patch (17.38 KB, patch)
2022-02-28 10:17 PST, Jer Noble
no flags Details | Formatted Diff | Diff
Patch (17.56 KB, patch)
2022-02-28 13:00 PST, Jer Noble
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jer Noble 2022-02-24 22:23:54 PST
[Cocoa] Allow logging to be configured by NSDefaults (without regressing launch time)
Comment 1 Jer Noble 2022-02-24 23:39:08 PST
Created attachment 453177 [details]
Patch
Comment 2 Jer Noble 2022-02-25 08:27:29 PST
Created attachment 453216 [details]
Patch
Comment 3 Jer Noble 2022-02-25 08:32:59 PST
Created attachment 453218 [details]
Patch
Comment 4 Jer Noble 2022-02-26 17:18:07 PST
Created attachment 453316 [details]
Patch
Comment 5 Jer Noble 2022-02-27 06:29:35 PST
Created attachment 453339 [details]
Patch
Comment 6 Darin Adler 2022-02-27 08:09:14 PST
Comment on attachment 453339 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=453339&action=review

> Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:53
> +String wtfLogLevelString()
> +{
> +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];
> +    return logString;
> +}
> +
> +String webCoreLogLevelString()
> +{
> +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
> +    return logString;
> +}
> +
> +String webKitLogLevelString()
> +{
> +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
> +    return logString;
> +}

We should not use NeverDestroyed here. That makes these non-thread-safe. There’s a reason we don’t do that in the WTF versions of these functions.

If there’s a performance problem with calling NSUserDefaults multiple times, and maybe that’s the whole point of the patch, we can cache the results, but we’d need a thread-safe way to do it, which would involve call_once and not using String for the cross-thread cached result. For example, we could use a NeverDestroyed<RetainPtr<NSString>> if we initialize it in a thread-safe manner, and create a new WTF::String each time these are called.

Unless I am missing something and these are always called on only a single thread? If so we should use the version of NeverDestroyed that includes that check perhaps?

> Source/WebKit/UIProcess/UIProcessLogInitialization.cpp:67
> +#if !PLATFORM(COCOA)
> +String wtfLogLevelString()
> +{
> +    static NeverDestroyed<String> logString = WTF::logLevelString();
> +    return logString;
> +}
> +
> +String webCoreLogLevelString()
> +{
> +    static NeverDestroyed<String> logString = WebCore::logLevelString();
> +    return logString;
> +}
> +
> +String webKitLogLevelString()
> +{
> +    static NeverDestroyed<String> logString = WebKit::logLevelString();
> +    return logString;
> +}
> +#endif

Ditto.
Comment 7 Jer Noble 2022-02-28 09:07:24 PST
(In reply to Darin Adler from comment #6)
> Comment on attachment 453339 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=453339&action=review
> 
> > Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:53
> > +String wtfLogLevelString()
> > +{
> > +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];
> > +    return logString;
> > +}
> > +
> > +String webCoreLogLevelString()
> > +{
> > +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
> > +    return logString;
> > +}
> > +
> > +String webKitLogLevelString()
> > +{
> > +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
> > +    return logString;
> > +}
> 
> We should not use NeverDestroyed here. That makes these non-thread-safe.
> There’s a reason we don’t do that in the WTF versions of these functions.
> 
> If there’s a performance problem with calling NSUserDefaults multiple times,
> and maybe that’s the whole point of the patch, we can cache the results, but
> we’d need a thread-safe way to do it, which would involve call_once and not
> using String for the cross-thread cached result. For example, we could use a
> NeverDestroyed<RetainPtr<NSString>> if we initialize it in a thread-safe
> manner, and create a new WTF::String each time these are called.
> 
> Unless I am missing something and these are always called on only a single
> thread? If so we should use the version of NeverDestroyed that includes that
> check perhaps?

Hah! I originally had std::call_once on each of these, but somehow thought that static NeverDestroyed initializers were thread safe. I'll change these back.

> > Source/WebKit/UIProcess/UIProcessLogInitialization.cpp:67
> > +#if !PLATFORM(COCOA)
> > +String wtfLogLevelString()
> > +{
> > +    static NeverDestroyed<String> logString = WTF::logLevelString();
> > +    return logString;
> > +}
> > +
> > +String webCoreLogLevelString()
> > +{
> > +    static NeverDestroyed<String> logString = WebCore::logLevelString();
> > +    return logString;
> > +}
> > +
> > +String webKitLogLevelString()
> > +{
> > +    static NeverDestroyed<String> logString = WebKit::logLevelString();
> > +    return logString;
> > +}
> > +#endif
> 
> Ditto.
Comment 8 Jer Noble 2022-02-28 09:11:46 PST
(In reply to Jer Noble from comment #7)
> (In reply to Darin Adler from comment #6)
> > Comment on attachment 453339 [details]
> > Patch
> > 
> > View in context:
> > https://bugs.webkit.org/attachment.cgi?id=453339&action=review
> > 
> > > Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:53
> > > +String wtfLogLevelString()
> > > +{
> > > +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];
> > > +    return logString;
> > > +}
> > > +
> > > +String webCoreLogLevelString()
> > > +{
> > > +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
> > > +    return logString;
> > > +}
> > > +
> > > +String webKitLogLevelString()
> > > +{
> > > +    static NeverDestroyed<String> logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
> > > +    return logString;
> > > +}
> > 
> > We should not use NeverDestroyed here. That makes these non-thread-safe.
> > There’s a reason we don’t do that in the WTF versions of these functions.
> > 
> > If there’s a performance problem with calling NSUserDefaults multiple times,
> > and maybe that’s the whole point of the patch, we can cache the results, but
> > we’d need a thread-safe way to do it, which would involve call_once and not
> > using String for the cross-thread cached result. For example, we could use a
> > NeverDestroyed<RetainPtr<NSString>> if we initialize it in a thread-safe
> > manner, and create a new WTF::String each time these are called.
> > 
> > Unless I am missing something and these are always called on only a single
> > thread? If so we should use the version of NeverDestroyed that includes that
> > check perhaps?
> 
> Hah! I originally had std::call_once on each of these, but somehow thought
> that static NeverDestroyed initializers were thread safe. I'll change these
> back.

(Also, while they are currently only ever called from the main thread, but there's no guarantee they will always be in the future, so best to make them thread safe now.)

> > > Source/WebKit/UIProcess/UIProcessLogInitialization.cpp:67
> > > +#if !PLATFORM(COCOA)
> > > +String wtfLogLevelString()
> > > +{
> > > +    static NeverDestroyed<String> logString = WTF::logLevelString();
> > > +    return logString;
> > > +}
> > > +
> > > +String webCoreLogLevelString()
> > > +{
> > > +    static NeverDestroyed<String> logString = WebCore::logLevelString();
> > > +    return logString;
> > > +}
> > > +
> > > +String webKitLogLevelString()
> > > +{
> > > +    static NeverDestroyed<String> logString = WebKit::logLevelString();
> > > +    return logString;
> > > +}
> > > +#endif
> > 
> > Ditto.
Comment 9 Jer Noble 2022-02-28 09:20:41 PST
Created attachment 453396 [details]
Patch
Comment 10 Jer Noble 2022-02-28 09:22:07 PST
Okay, these are all init'd behind a std::call_once or dispatchOnce.

Do we need similar modifications to emptyString() and nullString()?
Comment 11 Darin Adler 2022-02-28 09:46:37 PST
Comment on attachment 453396 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=453396&action=review

> Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:44
> +    static NeverDestroyed<String> logString;
> +    static dispatch_once_t onceToken;
> +    dispatch_once(&onceToken, ^{
> +        logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];
> +    });
> +    return logString;

This is insufficiently thread-safe. Sharing a String across threads still isn’t safe even if you initialize safely. But if logString was this:

    static NeverDestroyed<RetainPtr<NSString>> logString;

Then that would be thread-safe.

> Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:54
> +    static NeverDestroyed<String> logString;
> +    static dispatch_once_t onceToken;
> +    dispatch_once(&onceToken, ^{
> +        logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
> +    });
> +    return logString;

Ditto.

> Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:64
> +    static NeverDestroyed<String> logString;
> +    static dispatch_once_t onceToken;
> +    dispatch_once(&onceToken, ^{
> +        logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
> +    });
> +    return logString;

Ditto.

> Source/WebKit/UIProcess/UIProcessLogInitialization.cpp:57
> +    static NeverDestroyed<String> logString;
> +    static std::once_flag onceFlag;
> +    std::call_once(onceFlag, [] {
> +        logString = WTF::logLevelString();
> +    });
> +    return logString;

This isn’t thread-safe. The best solution is probably just to call WTF::logLevelString() every time.

> Source/WebKit/UIProcess/UIProcessLogInitialization.cpp:67
> +    static NeverDestroyed<String> logString;
> +    static std::once_flag onceFlag;
> +    std::call_once(onceFlag, [] {
> +        logString  = WebCore::logLevelString();
> +    });
> +    return logString;

Ditto.

> Source/WebKit/UIProcess/UIProcessLogInitialization.cpp:77
> +    static NeverDestroyed<String> logString;
> +    static std::once_flag onceFlag;
> +    std::call_once(onceFlag, [] {
> +        logString  = WebKit::logLevelString();
> +    });
> +    return logString;

Ditto.
Comment 12 Jer Noble 2022-02-28 09:50:49 PST
Created attachment 453400 [details]
Patch
Comment 13 Jer Noble 2022-02-28 09:58:20 PST
(In reply to Jer Noble from comment #12)
> Created attachment 453400 [details]
> Patch

Obsoleted because I only saw Darin's comments after uploading.

(In reply to Darin Adler from comment #11)
> Comment on attachment 453396 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=453396&action=review
> 
> > Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:44
> > +    static NeverDestroyed<String> logString;
> > +    static dispatch_once_t onceToken;
> > +    dispatch_once(&onceToken, ^{
> > +        logString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];
> > +    });
> > +    return logString;
> 
> This is insufficiently thread-safe. Sharing a String across threads still
> isn’t safe even if you initialize safely. But if logString was this:
> 
>     static NeverDestroyed<RetainPtr<NSString>> logString;
> 
> Then that would be thread-safe.

Ugh. It feels like WebKit needs a thread-safe platform-independent string class. It doesn't really feel like a great result if only ports with access to NSString can safely cache these values.

Alternatively, we can go back to an earlier suggestion and mandate these are only ever called from the main thread.
Comment 14 Jer Noble 2022-02-28 10:17:56 PST
Created attachment 453404 [details]
Patch
Comment 15 Jer Noble 2022-02-28 13:00:04 PST
Created attachment 453417 [details]
Patch
Comment 16 Darin Adler 2022-02-28 13:58:55 PST
Comment on attachment 453417 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=453417&action=review

> Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:42
> +        logString.get() = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];

Do we need the ".get()" on these lines?
Comment 17 Jer Noble 2022-02-28 14:42:37 PST
(In reply to Darin Adler from comment #16)
> Comment on attachment 453417 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=453417&action=review
> 
> > Source/WebKit/UIProcess/Cocoa/UIProcessLogInitializationCocoa.mm:42
> > +        logString.get() = [[NSUserDefaults standardUserDefaults] stringForKey:@"WTFLogging"];
> 
> Do we need the ".get()" on these lines?

Yes. Without them, you get a compile error about failing to infer the correct type and assignment operator.
Comment 18 EWS 2022-03-01 10:13:25 PST
Committed r290654 (247927@main): <https://commits.webkit.org/247927@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 453417 [details].
Comment 19 Radar WebKit Bug Importer 2022-03-01 10:14:17 PST
<rdar://problem/89626635>