Home | History | Annotate | Download | only in timing
      1 /*
      2  * Copyright (C) 2010 Google 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/timing/PerformanceTiming.h"
     33 
     34 #include "core/dom/Document.h"
     35 #include "core/dom/DocumentTiming.h"
     36 #include "core/frame/LocalFrame.h"
     37 #include "core/loader/DocumentLoadTiming.h"
     38 #include "core/loader/DocumentLoader.h"
     39 #include "core/loader/FrameLoader.h"
     40 #include "platform/network/ResourceLoadTiming.h"
     41 #include "platform/network/ResourceResponse.h"
     42 
     43 namespace blink {
     44 
     45 static unsigned long long toIntegerMilliseconds(double seconds)
     46 {
     47     ASSERT(seconds >= 0);
     48     return static_cast<unsigned long long>(seconds * 1000.0);
     49 }
     50 
     51 PerformanceTiming::PerformanceTiming(LocalFrame* frame)
     52     : DOMWindowProperty(frame)
     53 {
     54 }
     55 
     56 unsigned long long PerformanceTiming::navigationStart() const
     57 {
     58     DocumentLoadTiming* timing = documentLoadTiming();
     59     if (!timing)
     60         return 0;
     61 
     62     return monotonicTimeToIntegerMilliseconds(timing->navigationStart());
     63 }
     64 
     65 unsigned long long PerformanceTiming::unloadEventStart() const
     66 {
     67     DocumentLoadTiming* timing = documentLoadTiming();
     68     if (!timing)
     69         return 0;
     70 
     71     if (timing->hasCrossOriginRedirect() || !timing->hasSameOriginAsPreviousDocument())
     72         return 0;
     73 
     74     return monotonicTimeToIntegerMilliseconds(timing->unloadEventStart());
     75 }
     76 
     77 unsigned long long PerformanceTiming::unloadEventEnd() const
     78 {
     79     DocumentLoadTiming* timing = documentLoadTiming();
     80     if (!timing)
     81         return 0;
     82 
     83     if (timing->hasCrossOriginRedirect() || !timing->hasSameOriginAsPreviousDocument())
     84         return 0;
     85 
     86     return monotonicTimeToIntegerMilliseconds(timing->unloadEventEnd());
     87 }
     88 
     89 unsigned long long PerformanceTiming::redirectStart() const
     90 {
     91     DocumentLoadTiming* timing = documentLoadTiming();
     92     if (!timing)
     93         return 0;
     94 
     95     if (timing->hasCrossOriginRedirect())
     96         return 0;
     97 
     98     return monotonicTimeToIntegerMilliseconds(timing->redirectStart());
     99 }
    100 
    101 unsigned long long PerformanceTiming::redirectEnd() const
    102 {
    103     DocumentLoadTiming* timing = documentLoadTiming();
    104     if (!timing)
    105         return 0;
    106 
    107     if (timing->hasCrossOriginRedirect())
    108         return 0;
    109 
    110     return monotonicTimeToIntegerMilliseconds(timing->redirectEnd());
    111 }
    112 
    113 unsigned long long PerformanceTiming::fetchStart() const
    114 {
    115     DocumentLoadTiming* timing = documentLoadTiming();
    116     if (!timing)
    117         return 0;
    118 
    119     return monotonicTimeToIntegerMilliseconds(timing->fetchStart());
    120 }
    121 
    122 unsigned long long PerformanceTiming::domainLookupStart() const
    123 {
    124     ResourceLoadTiming* timing = resourceLoadTiming();
    125     if (!timing)
    126         return fetchStart();
    127 
    128     // This will be zero when a DNS request is not performed.
    129     // Rather than exposing a special value that indicates no DNS, we "backfill" with fetchStart.
    130     double dnsStart = timing->dnsStart;
    131     if (dnsStart == 0.0)
    132         return fetchStart();
    133 
    134     return monotonicTimeToIntegerMilliseconds(dnsStart);
    135 }
    136 
    137 unsigned long long PerformanceTiming::domainLookupEnd() const
    138 {
    139     ResourceLoadTiming* timing = resourceLoadTiming();
    140     if (!timing)
    141         return domainLookupStart();
    142 
    143     // This will be zero when a DNS request is not performed.
    144     // Rather than exposing a special value that indicates no DNS, we "backfill" with domainLookupStart.
    145     double dnsEnd = timing->dnsEnd;
    146     if (dnsEnd == 0.0)
    147         return domainLookupStart();
    148 
    149     return monotonicTimeToIntegerMilliseconds(dnsEnd);
    150 }
    151 
    152 unsigned long long PerformanceTiming::connectStart() const
    153 {
    154     DocumentLoader* loader = documentLoader();
    155     if (!loader)
    156         return domainLookupEnd();
    157 
    158     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
    159     if (!timing)
    160         return domainLookupEnd();
    161 
    162     // connectStart will be zero when a network request is not made.
    163     // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd.
    164     double connectStart = timing->connectStart;
    165     if (connectStart == 0.0 || loader->response().connectionReused())
    166         return domainLookupEnd();
    167 
    168     // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's
    169     // connect phase should not. So if there is DNS time, trim it from the start.
    170     if (timing->dnsEnd > 0.0 && timing->dnsEnd > connectStart)
    171         connectStart = timing->dnsEnd;
    172 
    173     return monotonicTimeToIntegerMilliseconds(connectStart);
    174 }
    175 
    176 unsigned long long PerformanceTiming::connectEnd() const
    177 {
    178     DocumentLoader* loader = documentLoader();
    179     if (!loader)
    180         return connectStart();
    181 
    182     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
    183     if (!timing)
    184         return connectStart();
    185 
    186     // connectEnd will be zero when a network request is not made.
    187     // Rather than exposing a special value that indicates no new connection, we "backfill" with connectStart.
    188     double connectEnd = timing->connectEnd;
    189     if (connectEnd == 0.0 || loader->response().connectionReused())
    190         return connectStart();
    191 
    192     return monotonicTimeToIntegerMilliseconds(connectEnd);
    193 }
    194 
    195 unsigned long long PerformanceTiming::secureConnectionStart() const
    196 {
    197     DocumentLoader* loader = documentLoader();
    198     if (!loader)
    199         return 0;
    200 
    201     ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
    202     if (!timing)
    203         return 0;
    204 
    205     double sslStart = timing->sslStart;
    206     if (sslStart == 0.0)
    207         return 0;
    208 
    209     return monotonicTimeToIntegerMilliseconds(sslStart);
    210 }
    211 
    212 unsigned long long PerformanceTiming::requestStart() const
    213 {
    214     ResourceLoadTiming* timing = resourceLoadTiming();
    215 
    216     if (!timing || timing->sendStart == 0.0)
    217         return connectEnd();
    218 
    219     return monotonicTimeToIntegerMilliseconds(timing->sendStart);
    220 }
    221 
    222 unsigned long long PerformanceTiming::responseStart() const
    223 {
    224     ResourceLoadTiming* timing = resourceLoadTiming();
    225     if (!timing || timing->receiveHeadersEnd == 0.0)
    226         return requestStart();
    227 
    228     // FIXME: Response start needs to be the time of the first received byte.
    229     // However, the ResourceLoadTiming API currently only supports the time
    230     // the last header byte was received. For many responses with reasonable
    231     // sized cookies, the HTTP headers fit into a single packet so this time
    232     // is basically equivalent. But for some responses, particularly those with
    233     // headers larger than a single packet, this time will be too late.
    234     return monotonicTimeToIntegerMilliseconds(timing->receiveHeadersEnd);
    235 }
    236 
    237 unsigned long long PerformanceTiming::responseEnd() const
    238 {
    239     DocumentLoadTiming* timing = documentLoadTiming();
    240     if (!timing)
    241         return 0;
    242 
    243     return monotonicTimeToIntegerMilliseconds(timing->responseEnd());
    244 }
    245 
    246 unsigned long long PerformanceTiming::domLoading() const
    247 {
    248     const DocumentTiming* timing = documentTiming();
    249     if (!timing)
    250         return fetchStart();
    251 
    252     return monotonicTimeToIntegerMilliseconds(timing->domLoading);
    253 }
    254 
    255 unsigned long long PerformanceTiming::domInteractive() const
    256 {
    257     const DocumentTiming* timing = documentTiming();
    258     if (!timing)
    259         return 0;
    260 
    261     return monotonicTimeToIntegerMilliseconds(timing->domInteractive);
    262 }
    263 
    264 unsigned long long PerformanceTiming::domContentLoadedEventStart() const
    265 {
    266     const DocumentTiming* timing = documentTiming();
    267     if (!timing)
    268         return 0;
    269 
    270     return monotonicTimeToIntegerMilliseconds(timing->domContentLoadedEventStart);
    271 }
    272 
    273 unsigned long long PerformanceTiming::domContentLoadedEventEnd() const
    274 {
    275     const DocumentTiming* timing = documentTiming();
    276     if (!timing)
    277         return 0;
    278 
    279     return monotonicTimeToIntegerMilliseconds(timing->domContentLoadedEventEnd);
    280 }
    281 
    282 unsigned long long PerformanceTiming::domComplete() const
    283 {
    284     const DocumentTiming* timing = documentTiming();
    285     if (!timing)
    286         return 0;
    287 
    288     return monotonicTimeToIntegerMilliseconds(timing->domComplete);
    289 }
    290 
    291 unsigned long long PerformanceTiming::loadEventStart() const
    292 {
    293     DocumentLoadTiming* timing = documentLoadTiming();
    294     if (!timing)
    295         return 0;
    296 
    297     return monotonicTimeToIntegerMilliseconds(timing->loadEventStart());
    298 }
    299 
    300 unsigned long long PerformanceTiming::loadEventEnd() const
    301 {
    302     DocumentLoadTiming* timing = documentLoadTiming();
    303     if (!timing)
    304         return 0;
    305 
    306     return monotonicTimeToIntegerMilliseconds(timing->loadEventEnd());
    307 }
    308 
    309 DocumentLoader* PerformanceTiming::documentLoader() const
    310 {
    311     if (!m_frame)
    312         return 0;
    313 
    314     return m_frame->loader().documentLoader();
    315 }
    316 
    317 const DocumentTiming* PerformanceTiming::documentTiming() const
    318 {
    319     if (!m_frame)
    320         return 0;
    321 
    322     Document* document = m_frame->document();
    323     if (!document)
    324         return 0;
    325 
    326     return &document->timing();
    327 }
    328 
    329 DocumentLoadTiming* PerformanceTiming::documentLoadTiming() const
    330 {
    331     DocumentLoader* loader = documentLoader();
    332     if (!loader)
    333         return 0;
    334 
    335     return loader->timing();
    336 }
    337 
    338 ResourceLoadTiming* PerformanceTiming::resourceLoadTiming() const
    339 {
    340     DocumentLoader* loader = documentLoader();
    341     if (!loader)
    342         return 0;
    343 
    344     return loader->response().resourceLoadTiming();
    345 }
    346 
    347 unsigned long long PerformanceTiming::monotonicTimeToIntegerMilliseconds(double monotonicSeconds) const
    348 {
    349     ASSERT(monotonicSeconds >= 0);
    350     const DocumentLoadTiming* timing = documentLoadTiming();
    351     if (!timing)
    352         return 0;
    353 
    354     return toIntegerMilliseconds(timing->monotonicTimeToPseudoWallTime(monotonicSeconds));
    355 }
    356 
    357 void PerformanceTiming::trace(Visitor* visitor)
    358 {
    359     DOMWindowProperty::trace(visitor);
    360 }
    361 
    362 } // namespace blink
    363