1/* 2 * Copyright (C) 2012 Intel Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "PerformanceUserTiming.h" 28 29#if ENABLE(USER_TIMING) 30 31#include "Performance.h" 32#include "PerformanceMark.h" 33#include "PerformanceMeasure.h" 34#include <wtf/dtoa/utils.h> 35#include <wtf/text/WTFString.h> 36 37namespace WebCore { 38 39namespace { 40 41typedef HashMap<String, NavigationTimingFunction> RestrictedKeyMap; 42static RestrictedKeyMap restrictedKeyMap() 43{ 44 DEFINE_STATIC_LOCAL(RestrictedKeyMap, map, ()); 45 if (map.isEmpty()) { 46 map.add("navigationStart", &PerformanceTiming::navigationStart); 47 map.add("unloadEventStart", &PerformanceTiming::unloadEventStart); 48 map.add("unloadEventEnd", &PerformanceTiming::unloadEventEnd); 49 map.add("redirectStart", &PerformanceTiming::redirectStart); 50 map.add("redirectEnd", &PerformanceTiming::redirectEnd); 51 map.add("fetchStart", &PerformanceTiming::fetchStart); 52 map.add("domainLookupStart", &PerformanceTiming::domainLookupStart); 53 map.add("domainLookupEnd", &PerformanceTiming::domainLookupEnd); 54 map.add("connectStart", &PerformanceTiming::connectStart); 55 map.add("connectEnd", &PerformanceTiming::connectEnd); 56 map.add("secureConnectionStart", &PerformanceTiming::secureConnectionStart); 57 map.add("requestStart", &PerformanceTiming::requestStart); 58 map.add("responseStart", &PerformanceTiming::responseStart); 59 map.add("responseEnd", &PerformanceTiming::responseEnd); 60 map.add("domLoading", &PerformanceTiming::domLoading); 61 map.add("domInteractive", &PerformanceTiming::domInteractive); 62 map.add("domContentLoadedEventStart", &PerformanceTiming::domContentLoadedEventStart); 63 map.add("domContentLoadedEventEnd", &PerformanceTiming::domContentLoadedEventEnd); 64 map.add("domComplete", &PerformanceTiming::domComplete); 65 map.add("loadEventStart", &PerformanceTiming::loadEventStart); 66 map.add("loadEventEnd", &PerformanceTiming::loadEventEnd); 67 } 68 return map; 69} 70 71} // namespace anonymous 72 73UserTiming::UserTiming(Performance* performance) 74 : m_performance(performance) 75{ 76} 77 78static void insertPerformanceEntry(PerformanceEntryMap& performanceEntryMap, PassRefPtr<PerformanceEntry> performanceEntry) 79{ 80 RefPtr<PerformanceEntry> entry = performanceEntry; 81 PerformanceEntryMap::iterator it = performanceEntryMap.find(entry->name()); 82 if (it != performanceEntryMap.end()) 83 it->value.append(entry); 84 else { 85 Vector<RefPtr<PerformanceEntry> > v(1); 86 v[0] = entry; 87 performanceEntryMap.set(entry->name(), v); 88 } 89} 90 91static void clearPeformanceEntries(PerformanceEntryMap& performanceEntryMap, const String& name) 92{ 93 if (name.isNull()) { 94 performanceEntryMap.clear(); 95 return; 96 } 97 98 if (performanceEntryMap.contains(name)) 99 performanceEntryMap.remove(name); 100} 101 102void UserTiming::mark(const String& markName, ExceptionCode& ec) 103{ 104 ec = 0; 105 if (restrictedKeyMap().contains(markName)) { 106 ec = SYNTAX_ERR; 107 return; 108 } 109 110 double startTime = m_performance->now(); 111 insertPerformanceEntry(m_marksMap, PerformanceMark::create(markName, startTime)); 112} 113 114void UserTiming::clearMarks(const String& markName) 115{ 116 clearPeformanceEntries(m_marksMap, markName); 117} 118 119double UserTiming::findExistingMarkStartTime(const String& markName, ExceptionCode& ec) 120{ 121 ec = 0; 122 123 if (m_marksMap.contains(markName)) 124 return m_marksMap.get(markName).last()->startTime(); 125 126 if (restrictedKeyMap().contains(markName)) { 127 double value = static_cast<double>((m_performance->timing()->*(restrictedKeyMap().get(markName)))()); 128 if (!value) { 129 ec = INVALID_ACCESS_ERR; 130 return 0.0; 131 } 132 return value - m_performance->timing()->navigationStart(); 133 } 134 135 ec = SYNTAX_ERR; 136 return 0.0; 137} 138 139void UserTiming::measure(const String& measureName, const String& startMark, const String& endMark, ExceptionCode& ec) 140{ 141 double startTime = 0.0; 142 double endTime = 0.0; 143 144 if (startMark.isNull()) 145 endTime = m_performance->now(); 146 else if (endMark.isNull()) { 147 endTime = m_performance->now(); 148 startTime = findExistingMarkStartTime(startMark, ec); 149 if (ec) 150 return; 151 } else { 152 endTime = findExistingMarkStartTime(endMark, ec); 153 if (ec) 154 return; 155 startTime = findExistingMarkStartTime(startMark, ec); 156 if (ec) 157 return; 158 } 159 160 insertPerformanceEntry(m_measuresMap, PerformanceMeasure::create(measureName, startTime, endTime)); 161} 162 163void UserTiming::clearMeasures(const String& measureName) 164{ 165 clearPeformanceEntries(m_measuresMap, measureName); 166} 167 168static Vector<RefPtr<PerformanceEntry> > convertToEntrySequence(const PerformanceEntryMap& performanceEntryMap) 169{ 170 Vector<RefPtr<PerformanceEntry> > entries; 171 172 for (PerformanceEntryMap::const_iterator it = performanceEntryMap.begin(); it != performanceEntryMap.end(); ++it) 173 entries.appendVector(it->value); 174 175 return entries; 176} 177 178static Vector<RefPtr<PerformanceEntry> > getEntrySequenceByName(const PerformanceEntryMap& performanceEntryMap, const String& name) 179{ 180 Vector<RefPtr<PerformanceEntry> > entries; 181 182 PerformanceEntryMap::const_iterator it = performanceEntryMap.find(name); 183 if (it != performanceEntryMap.end()) 184 entries.appendVector(it->value); 185 186 return entries; 187} 188 189Vector<RefPtr<PerformanceEntry> > UserTiming::getMarks() const 190{ 191 return convertToEntrySequence(m_marksMap); 192} 193 194Vector<RefPtr<PerformanceEntry> > UserTiming::getMarks(const String& name) const 195{ 196 return getEntrySequenceByName(m_marksMap, name); 197} 198 199Vector<RefPtr<PerformanceEntry> > UserTiming::getMeasures() const 200{ 201 return convertToEntrySequence(m_measuresMap); 202} 203 204Vector<RefPtr<PerformanceEntry> > UserTiming::getMeasures(const String& name) const 205{ 206 return getEntrySequenceByName(m_measuresMap, name); 207} 208 209} // namespace WebCore 210 211#endif // ENABLE(USER_TIMING) 212