Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Unified Diff: third_party/WebKit/Source/core/events/EventDispatcher.cpp

Issue 1835303002: Implementation of the GreenWeb language extensions. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Change GreenWeb-related CSS property names such that they apply in the desired order at runtime. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/events/EventDispatcher.cpp
diff --git a/third_party/WebKit/Source/core/events/EventDispatcher.cpp b/third_party/WebKit/Source/core/events/EventDispatcher.cpp
index d069a1c9915fdbd64d5f4580fc562e9c1d86c480..d591daba67ead31ad67e418a438e24971c1fe545 100644
--- a/third_party/WebKit/Source/core/events/EventDispatcher.cpp
+++ b/third_party/WebKit/Source/core/events/EventDispatcher.cpp
@@ -26,9 +26,14 @@
#include "config.h"
#include "core/events/EventDispatcher.h"
+#include <iostream>
+#include <string>
+
+#include "content/renderer/greenweb_latency_tracking.h"
#include "core/dom/ContainerNode.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
+#include "core/dom/NodeComputedStyle.h"
#include "core/events/EventDispatchMediator.h"
#include "core/events/MouseEvent.h"
#include "core/events/ScopedEventQueue.h"
@@ -36,10 +41,15 @@
#include "core/frame/FrameView.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/inspector/InspectorTraceEvents.h"
+#include "core/style/ComputedStyle.h"
#include "platform/EventDispatchForbiddenScope.h"
#include "platform/TraceEvent.h"
#include "wtf/RefPtr.h"
+char g_qos_type = 'u';
+int g_qos_target = 0;
+bool g_ebs_enabled = false;
+
namespace blink {
bool EventDispatcher::dispatchEvent(Node& node, PassRefPtrWillBeRawPtr<EventDispatchMediator> mediator)
@@ -102,6 +112,320 @@ void EventDispatcher::dispatchSimulatedClick(Node& node, Event* underlyingEvent,
nodesDispatchingSimulatedClicks->remove(&node);
}
+bool init_ebs(bool *mode)
+{
+ FILE* arg_file;
+ arg_file = fopen("/data/local/tmp/chrome-shell-command-line", "r");
+ if (!arg_file) {
+ dbg_sched_fprintf(stdout, "[EBS] arg file open failed\n");
+ return false;
+ }
+ dbg_sched_fprintf(stdout, "[EBS] arg file opened\n");
+
+ char arg_list[100];
+ fgets(arg_list, 100, arg_file);
+ fclose(arg_file);
+
+ if (arg_list[13] == '-'
+ && arg_list[14] == '-'
+ && arg_list[15] == 'e'
+ && arg_list[16] == 'b'
+ && arg_list[17] == 's'
+ && arg_list[18] == '-'
+ && arg_list[19] == 'p')
+ {
+ if (arg_list[20] == 'i') {
+ *mode = true;
+ dbg_sched_fprintf(stdout, "[EBS] ebs enabled. Using Pi\n");
+ return true;
+ }
+ if (arg_list[20] == 'u') {
+ *mode = false;
+ dbg_sched_fprintf(stdout, "[EBS] ebs enabled. Using Pu\n");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void set_freq(uint32 freq)
+{
+ FILE* cpufreq = NULL;
+
+ if (!cpufreq) {
+ cpufreq = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed", "w");
+ if (!cpufreq)
+ dbg_sched_fprintf(stdout, "[EBS] file open failed\n");
+ else
+ dbg_sched_fprintf(stdout, "[EBS] freq file open succeeded\n");
+ }
+
+ if (cpufreq) {
+ int bytes = fprintf(cpufreq, "%u", freq);
+ if ((bytes != 6) && (bytes != 7)) {
+ dbg_sched_fprintf(stdout, "[EBS] cpufreq not set\n");
+ } else {
+ dbg_sched_fprintf(stdout, "[EBS] freq set to %d\n", freq);
+#ifdef EBS_DEBUG_TRACE_EVENT
+ TRACE_EVENT2("devtools.timeline", "EBS:Schedule",
+ "log", "freq set",
+ "freq", freq);
+#endif
+ }
+ fclose(cpufreq);
+ }
+}
+
+void schedule(uint32 last_state, int64 last_latency, uint32 *next_state, uint32 *next_freq, int qos_target, FreqLatencyMap *freq_map, int64 dom_node_id)
+{
+ // FSM state explanation:
+ // 0xFF - Calibrating on big core, 1.6G
+ // 0x00 - Calibrating on big core, 0.8G
+ // 0x01 - Calibrating on little core, 0.6G
+ // 0x02 - Calibrating on little core, 0.4G
+ // 0xN - Running on core with frequency N/10 GHz (N = 3~16)
+
+ // First time we run an event on this node. Run with 1.6G.
+ // ODroid doesn't allow setting all 4 cores to 1.8G.
+ if (last_latency == 0) {
+ *next_state = 0xFF;
+ *next_freq = 1600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Now calibrate on 1.6G\n", last_state, *next_state);
+ return;
+ }
+
+ // Second time we run an event on this node. Run with 0.8G.
+ if (last_state == 0xFF) {
+ *next_state = 0;
+ *next_freq = 800000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Now calibrate on 0.8G\n", last_state, *next_state);
+ } else if (last_state == 0) {
+ // Finished the two profiling runs on the big core.
+ int64 time_8 = (*freq_map)[800000];
+ int64 time_16 = (*freq_map)[1600000];
+
+ if (qos_target <= time_16) {
+ // Have to provision the highest conf.
+ *next_state = 16;
+ *next_freq = 1600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: T16 > Target. Have to use the highest big\n", last_state, *next_state);
+ } else if (qos_target >= time_8) {
+ // Try the little core
+ *next_state = 1;
+ *next_freq = 600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: T8 < Target. Now calibrate on 0.6G\n", last_state, *next_state);
+ } else {
+ if (time_8 <= time_16) {
+ // Recalibrate on the big core
+ *next_state = 0xFF;
+ *next_freq = 1600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: T8 < T16. Recalibrate on big\n", last_state, *next_state);
+ } else {
+ double beta = (time_8 - time_16) * 1.6 * 1000000;
+ double alpha = time_8 - beta / 800000;
+ *next_freq = (int)(beta / (qos_target - alpha) + 1) / 100000 * 100000;
+ *next_state = *next_freq / 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: On big, predicted by model\n", last_state, *next_state);
+ }
+ }
+ } else if (last_state == 1) {
+ // First profiling run on the little core.
+ *next_state = 2;
+ // Never uses 300 MHz, beucase it leads to more energy than 400 MHz
+ *next_freq = 400000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Now calibrate on 0.4G\n", last_state, *next_state);
+ } else if (last_state == 2) {
+ // Finished the two profiling runs on the little core.
+ int64 time_4 = (*freq_map)[400000];
+ int64 time_6 = (*freq_map)[600000];
+
+ if (qos_target <= time_6) {
+ // Recalibrate on the big core
+ *next_state = 0xFF;
+ *next_freq = 1600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: T6 > Target. Recalibrate on big\n", last_state, *next_state);
+ } else if (qos_target >= time_4) {
+ // It's safe to provision the lowest on the little core
+ *next_state = 4;
+ *next_freq = 400000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: T4 < Target. Safe to use the lowest little\n", last_state, *next_state);
+ } else {
+ if (time_4 <= time_6) {
+ // Recalibrate on the little core
+ *next_state = 1;
+ *next_freq = 600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: T4 < T6. Recalibrate on little\n", last_state, *next_state);
+ } else {
+ double beta = (time_4 - time_6) * 1.2 * 1000000;
+ double alpha = time_4 - beta / 400000;
+ *next_freq = (int)(beta / (qos_target - alpha) + 1) / 100000 * 100000;
+ *next_state = *next_freq / 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: On little, predicted by model\n", last_state, *next_state);
+ }
+ }
+ } else {
+ // Fine tune phase, depending on the last_latency.
+ static std::map<int64, int> underpred;
+ static std::map<int64, int> overpred;
+
+ if (last_latency < qos_target * 0.8) {
+ // Overpredicting
+ if (last_state == 4) {
+ // Already lowest. Nothing we can do.
+ *next_state = last_state;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Keep the last prediction\n", last_state, *next_state);
+ return;
+ }
+
+ underpred[dom_node_id] = 0;
+ overpred[dom_node_id]++;
+
+ if (overpred[dom_node_id] <= 2) {
+ if (last_state == 4)
+ *next_state = 4;
+ else if (last_state == 8)
+ *next_state = 6;
+ else
+ *next_state = last_state - 1;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Overpredict\n", last_state, *next_state);
+ } else if (overpred[dom_node_id] <= 4) {
+ if (last_state <= 5)
+ *next_state = 4;
+ else if (last_state == 9)
+ *next_state = 6;
+ else
+ *next_state = last_state - 2;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Too many overpredict\n", last_state, *next_state);
+ } else {
+ overpred[dom_node_id] = 0;
+ *next_state = 0xFF;
+ *next_freq = 1600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Way too many overpredict\n", last_state, *next_state);
+ }
+ } else if (last_latency > qos_target * 0.9) {
+ // Underpredicting
+ if (last_state == 16) {
+ // Already highest. Nothing we can do.
+ *next_state = last_state;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Keep the last prediction\n", last_state, *next_state);
+ return;
+ }
+
+ overpred[dom_node_id] = 0;
+ underpred[dom_node_id]++;
+
+ if (underpred[dom_node_id] <= 2) {
+ if (last_state == 16)
+ *next_state = 16;
+ else if (last_state == 6)
+ *next_state = 8;
+ else
+ *next_state = last_state + 1;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Underpredict\n", last_state, *next_state);
+ } else if (underpred[dom_node_id] <= 4) {
+ if (last_state >= 15)
+ *next_state = 16;
+ else if (last_state == 5)
+ *next_state = 8;
+ else
+ *next_state = last_state + 2;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Too many underpredict\n", last_state, *next_state);
+ } else {
+ underpred[dom_node_id] = 0;
+ *next_state = 0xFF;
+ *next_freq = 1600000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Way too many underpredict\n", last_state, *next_state);
+ }
+ } else {
+ overpred[dom_node_id] = 0;
+ underpred[dom_node_id] = 0;
+ *next_state = last_state;
+ *next_freq = (*next_state) * 100000;
+ dbg_sched_fprintf(stdout, "[EBS] state %d --> %d: Keep the last prediction\n", last_state, *next_state);
+ }
+ }
+
+#ifdef EBS_DEBUG_TRACE_EVENT
+ TRACE_EVENT2("devtools.timeline", "EBS:Schedule",
+ "last_state", last_state,
+ "next_state", *next_state);
+#endif
+}
+
+int isEventSupported(String event_name)
+{
+ if (event_name == "click")
+ return 1;
+ else if(event_name == "touchstart")
+ return 2;
+ else if(event_name == "touchend")
+ return 3;
+ else if(event_name == "scroll")
+ return 4;
+ else if(event_name == "touchmove")
+ return 5;
+ return 0;
+}
+
+void EventDispatcher::retriveQoSInfo(bool mode, int event)
+{
+ int pi, pu, type;
+
+ // TODO: handle cases where multiple events register callbacks on one node
+ switch (event) {
+ case 1: // click
+ pi = m_node->computedStyle()->onclickVpi();
+ pu = m_node->computedStyle()->onclickVpu();
+ type = m_node->computedStyle()->onclickType();
+ break;
+ case 2: // touchstart
+ pi = m_node->computedStyle()->ontouchstartVpi();
+ pu = m_node->computedStyle()->ontouchstartVpu();
+ type = m_node->computedStyle()->ontouchstartType();
+ break;
+ case 3: // touchend
+ pi = m_node->computedStyle()->ontouchendVpi();
+ pu = m_node->computedStyle()->ontouchendVpu();
+ type = m_node->computedStyle()->ontouchendType();
+ break;
+ case 4: // scroll
+ pi = m_node->computedStyle()->onscrollVpi();
+ pu = m_node->computedStyle()->onscrollVpu();
+ type = m_node->computedStyle()->onscrollType();
+ break;
+ case 5: // touchmove
+ pi = m_node->computedStyle()->ontouchmoveVpi();
+ pu = m_node->computedStyle()->ontouchmoveVpu();
+ type = m_node->computedStyle()->ontouchmoveType();
+ break;
+ default: // Should never reach here
+ dbg_sched_fprintf(stdout, "[EBS] Wrong event id. Should never reach here!\n");
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ g_qos_target = mode ? pi : pu;
+
+ std::string QoSType;
+ if (type == 0)
+ QoSType = "single";
+ else
+ QoSType = "continuous";
+ g_qos_type = QoSType[0];
+
+ dbg_sched_cout("Node " << m_node->nodeName().utf8().data() <<
+ " on" << m_event->type().string().utf8().data() <<
+ ": (" << QoSType << ")" <<
+ " [" << pi << ", " << pu << "]");
+}
+
bool EventDispatcher::dispatch()
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.debug"), "EventDispatcher::dispatch");
@@ -120,6 +444,97 @@ bool EventDispatcher::dispatch()
ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
ASSERT(m_event->target());
TRACE_EVENT1("devtools.timeline", "EventDispatch", "data", InspectorEventDispatchEvent::data(*m_event));
+
+ static bool init = false;
+ static bool mode = true; // true-Pi, false-Pu
+
+ if (!init) {
+ init = true;
+ g_ebs_enabled = init_ebs(&mode);
+ }
+
+ String event_name = m_event->type().string();
+ int event_id = isEventSupported(event_name);
+ if (event_id) {
+ int64 dom_node_id = reinterpret_cast<int64>(m_node.get());
+ InputLatencyMap[InputLatencyID].dom_node = dom_node_id;
+
+ if (g_ebs_enabled && m_node->computedStyle()) {
+ retriveQoSInfo(mode, event_id);
+
+ // Deal with the single QoS type here. The GPU process deals with the continuous case.
+ if (g_qos_type == 's') {
+ // Memoize the freq to latency mapping for each DOM node.
+ // Used for constructing/calibrating the model and prediction.
+ // Data structure: std::map<int64, std::map<uint32, int64>>
+ static NodeFreqLatencyMap EBSCoreMap;
+ // Memoize the latency, state, and freq for each DOM node
+ // when it was executed last time.
+ static std::map<int64, int64> last_latency;
+ static std::map<int64, uint32> last_state;
+ static std::map<int64, uint32> last_freq;
+
+ uint32 last_state_t = last_state[dom_node_id];
+ uint32 last_freq_t = last_freq[dom_node_id];
+
+ if (DOMLatencyMap.find(dom_node_id) != DOMLatencyMap.end()) {
+ // Updating last_latency of this DOM node.
+ // This could not be done eagerly before it's actually executed.
+ last_latency[dom_node_id] = DOMLatencyMap[dom_node_id].latency;
+ EBSCoreMap[dom_node_id][last_freq_t] = last_latency[dom_node_id];
+ }
+#ifdef EBS_DEBUG_TRACE_EVENT
+ TRACE_EVENT2("devtools.timeline", "GreenWeb:EventDispatch",
+ "trace_id", InputLatencyID,
+ "last_latency", DOMLatencyMap[dom_node_id].latency);
+#endif
+ dbg_sched_cout("[EBS] trace_id " << InputLatencyID <<
+ " dom_node " << dom_node_id <<
+ " last_freq " << last_freq_t <<
+ " last_latency " << DOMLatencyMap[dom_node_id].latency);
+
+ uint32 next_state;
+ uint32 next_freq;
+ int64 last_latency_t = last_latency[dom_node_id];
+
+ schedule(last_state_t,
+ last_latency_t,
+ &next_state,
+ &next_freq,
+ g_qos_target,
+ &EBSCoreMap[dom_node_id],
+ dom_node_id);
+ set_freq(next_freq);
+
+ // Early updating last_state and last_freq of this DOM node.
+ // Next time we see this DOM node, its last_state and last_freq
+ // is the next_state and next_freq set in the previous run.
+ // Note that the last_latency of a DOM node can only be set
+ // when it's seen the next time -- it has to be executed before
+ // we know it's latency!
+ last_state[dom_node_id] = next_state;
+ last_freq[dom_node_id] = next_freq;
+ }
+ } else { // EBS not enabled
+#ifdef EBS_DEBUG_OS
+ std::cout << "[OS] dom_node " << dom_node_id << " last_latency " << DOMLatencyMap[dom_node_id].latency << std::endl;
+ for (int i = 4; i <= 16; i++) {
+ if (i == 7)
+ continue;
+ std::cout << i * 100000 << " " << DOMLatencyMap[dom_node_id].FreqStatMap[i * 100000] << std::endl;
+ }
+ fprintf(stdout, " \n");
+#endif
+ }
+ }
+
+ static int counter_s = 0;
+ if ((counter_s != 4) && !strcmp(m_event->type().string().utf8().data(), "readystatechange")) {
+ if (++counter_s == 4)
+ fprintf(stdout, "PageStart\n");
+ }
+ fflush(stdout);
+
void* preDispatchEventHandlerResult;
if (dispatchEventPreProcess(preDispatchEventHandlerResult) == ContinueDispatching) {
if (dispatchEventAtCapturing() == ContinueDispatching) {
« no previous file with comments | « third_party/WebKit/Source/core/events/EventDispatcher.h ('k') | third_party/WebKit/Source/core/frame/UseCounter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698