summaryrefslogtreecommitdiff
path: root/src/vm/perfdefaults.cpp
blob: fe50d3b5fa801a4f5018568492f39cb10b1ad6ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//*************************************************************************************************
// PerfDefaults.cpp
// 

// 
// Implementation of the "PerformanceScenario" config option, which defines a workload-specific 
// set of performance defaults.  The key point of the code below is that it be clear exactly what 
// gets enabled for each scenario -- see the switch statements
//
//     for host STARTUP_FLAGS, in GetModifiedStartupFlags
//     for environment, registry, or config CLRConfig values, in LookupConfigValue
//     for other global initialization, in InitializeForScenario
//
//*************************************************************************************************

#include "common.h"
#include "perfdefaults.h"

// Useful to the readability of lists of settings below
#define MATCHES(a,b) (SString::_wcsicmp((a),(b)) == 0)

// The scenario we have been asked to run under
PerformanceDefaults::PerformanceScenario PerformanceDefaults::s_Scenario = Uninitialized;

// See use in code:PerformanceDefaults:InitializeForScenario
extern int32_t g_bLowMemoryFromHost;


//
// Initialize our system to provide performance defaults for a given scenario.
// If the scenario name is not recognized, intentionally ignore it and operate as if not specified.
//
 void PerformanceDefaults::InitializeForScenario(__in_opt LPWSTR scenarioName)
{
    LIMITED_METHOD_CONTRACT;

    // First convert the scenario name to the corresponding enum value
    s_Scenario = None;
    if (scenarioName != NULL)
    {
        if (MATCHES(scenarioName, W("HighDensityWebHosting"))) s_Scenario = HighDensityWebHosting;
    }

    // Next do any scenario-specific initialization
    switch (s_Scenario)
    {
        case None:
            break;

        case HighDensityWebHosting:
            // Tell the hosting API that we want the GC to operate as if the machine is under memory pressure.
            // This is a workaround because we do not want to expose "force low memory mode" as either a CLR
            // config option or a host startup flag (the two types of knob that PerformanceDefaults can alter) and
            // ASP.Net has not yet become a memory host.  When they do, this can be removed and they can
            // make an initial call to ICLRMemoryNotificationCallback:OnMemoryNotification(eMemoryAvailableLow).
            //
            // Note that in order for ASP.Net to become a memory host the CLR will need to support profiler attach
            // in that condition.
            g_bLowMemoryFromHost = 1;
            break;

        case Uninitialized:
            // Unreachable, but make GCC happy
            break;
    }

    // Finally register our lookup function with the CLRConfig system so we get called when a 'MayHavePerformanceDefault' 
    // config option is about to resolve to its runtime default
    if (s_Scenario != None)
    {
        CLRConfig::RegisterGetPerformanceDefaultValueCallback(&LookupConfigValue);
    }
}


//
// Called at runtime startup to allow host-specified STARTUP_FLAGS to be overridden when running
// under a scenario.
//
// Note that we are comfortable overriding the values the host has asked us to use (see
// file:PerfDefaults.h), but we never want to override a value specified by a user to CLRConfig.
// This comes up here because there are settings that are configurable through both systems.
// So where an option has both STARTUP_FLAG A and CLRConfig value B, first check whether B has
// been specified before altering the value of A.  This way, we maintain complete compatibility
// with whatever the interaction of A and B has produced in the past.
//
STARTUP_FLAGS PerformanceDefaults::GetModifiedStartupFlags(STARTUP_FLAGS originalFlags)
{
    LIMITED_METHOD_CONTRACT;

    DWORD newFlags = (DWORD)originalFlags;

    switch (s_Scenario)
    {
        case None:
            break;

        case HighDensityWebHosting:
            if (!CLRConfig::IsConfigOptionSpecified(W("gcServer"))) newFlags &= ~STARTUP_SERVER_GC;
            if (!CLRConfig::IsConfigOptionSpecified(W("gcConcurrent"))) newFlags &= ~STARTUP_CONCURRENT_GC;
            if (!CLRConfig::IsConfigOptionSpecified(W("gcTrimCommitOnLowMemory"))) newFlags |= STARTUP_TRIM_GC_COMMIT;

            break;

        case Uninitialized:
            // Check that no request for startup flags happens before our code has been initialized 
            // and given a chance to modify them.
            _ASSERTE(!"PerformanceDefaults::InitializeForScenario should have already been called");
            break;
    }

    return (STARTUP_FLAGS)newFlags;
}


//
// Called by the CLRConfig system whenever a 'MayHavePerformanceDefault' config option is about 
// to resolve to its runtime default (i.e. none of the corresponding environment variable, registry, or
// config file values were specified).
//
BOOL PerformanceDefaults::LookupConfigValue(LPCWSTR name, DWORD *pValue)
{
    LIMITED_METHOD_CONTRACT;
    _ASSERTE(pValue != NULL);

    switch (s_Scenario)
    {
        case None:
            return FALSE;
    
        case HighDensityWebHosting:
            if (MATCHES(name, W("shadowCopyVerifyByTimestamp"))) { *pValue = 1; return TRUE; }
            return FALSE;

        case Uninitialized:
            // Check that no request for a MayHavePerformanceDefault CLRConfig option happens 
            // before our code has been initialized and given a chance to provide a default value.
            _ASSERTE(!"PerformanceDefaults::InitializeForScenario should have already been called");
            break;
    }

    return FALSE;
}