Package org.auraframework.test.perf.rdp

Source Code of org.auraframework.test.perf.rdp.RDPAnalyzer

/*
* Copyright (C) 2013 salesforce.com, inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.auraframework.test.perf.rdp;

import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.auraframework.test.perf.PerfUtil;
import org.auraframework.test.perf.metrics.PerfMetric;
import org.auraframework.test.perf.rdp.RDP.Domain;
import org.auraframework.test.perf.rdp.RDP.Network;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
* Analyzes the raw RDP notifications
*/
public final class RDPAnalyzer {

    protected static final Logger LOG = Logger.getLogger(RDPAnalyzer.class.getSimpleName());

    private final List<RDPNotification> notifications;
    private final List<RDPNotification> filteredNotifications;
    private final List<JSONObject> filteredFlattenedTimelineEvents;
    private Map<String, TimelineEventStats> timelineEventsStats;

    public RDPAnalyzer(List<RDPNotification> notifications, String startMarker, String endMarker) {
        this.notifications = notifications;
        filteredNotifications = RDPUtil.filteredNotifications(notifications, startMarker, endMarker);

        List<JSONObject> flattenedTimelineEvents = RDPUtil.flattenedTimelineEvents(notifications);
        this.filteredFlattenedTimelineEvents = RDPUtil
                .filteredTimeline(flattenedTimelineEvents, startMarker, endMarker);

        LOG.info("num timeline events: " + flattenedTimelineEvents.size() + ", num filtered: "
                + this.filteredFlattenedTimelineEvents.size());
    }

    public List<RDPNotification> getFilteredNotifications() {
        return filteredNotifications;
    }

    public List<JSONObject> getFilteredFlattenedTimelineEvents() {
        return filteredFlattenedTimelineEvents;
    }

    /**
     * Collecs statistics on all the "Timeline.eventRecorded" events
     */
    public synchronized Map<String, TimelineEventStats> analyzeTimelineDomain() {
        if (timelineEventsStats != null) {
            return timelineEventsStats;
        }

        timelineEventsStats = Maps.newHashMap();
        for (JSONObject timelineEvent : filteredFlattenedTimelineEvents) {
            try {
                collectTimelineEvent(timelineEvent);
            } catch (Exception e) {
                LOG.log(Level.WARNING, String.valueOf(timelineEvent), e);
            }
        }
        return timelineEventsStats;
    }

    /**
     * @param timeline event, see
     *            https://developers.google.com/chrome-developer-tools/docs/protocol/tot/timeline#type-TimelineEvent
     */
    private void collectTimelineEvent(JSONObject timelineEvent) throws JSONException {
        // add event itself
        String type = timelineEvent.getString("type");

        // times are of this form "1.3976003351068398E12"
        String startTime = timelineEvent.getString("startTime");
        long elapsedMicros = 0;
        if (timelineEvent.has("endTime")) {
            elapsedMicros = PerfUtil.elapsedMicros(startTime, timelineEvent.getString("endTime"));
        } else {
            // TODO: events without endTime
        }

        TimelineEventStats stats = timelineEventsStats.get(type);
        if (stats == null) {
            stats = new TimelineEventStats(type);
            timelineEventsStats.put(type, stats);
        }
        stats.addEvent(elapsedMicros);

        // collect event details
        JSONObject details = timelineEvent.getJSONObject("data");
        if (details != null && details.length() > 0) {
            stats.addDetails(timelineEvent.getJSONObject("data"));
        }
    }

    /**
     * Analyzes the Network domain events and returns a set of PerfMetrics derived from them
     */
    public List<PerfMetric> analyzeNetworkDomain() {
        // Sequence and relevant fields:
        // requestWillBeSent: timestamp requestId params.documentURL
        // responseReceived: timestamp params.requestId params.response.timing?
        // dataReceived+: timestamp params.requestId params.dataLength params.encodedDataLength
        // loadingFinished/Failed: timestamp params.requestId params.encodedDataLength?

        // collect the following metrics:
        // numRequests: details: documentURL + size
        // totalEncodedDataLength: details: documentURL+size
        Map<String, JSONObject> requestIdToDetail = Maps.newHashMap();
        int numRequests = 0;
        int totalEncodedDataLength = 0;
        JSONArray details = new JSONArray();
        for (RDPNotification notification : RDPUtil.filterNotifications(filteredNotifications, Domain.Network)) {
            try {
                String method = notification.getMethod();
                JSONObject params = notification.getParams();
                if (Network.requestWillBeSent.equals(method)) {
                    JSONObject request = params.getJSONObject("request");
                    JSONObject detail = new JSONObject();
                    detail.put("url", request.getString("url"));
                    detail.put("method", request.getString("method"));
                    detail.put("encodedDataLength", 0);
                    requestIdToDetail.put(params.getString("requestId"), detail);
                    continue;
                }

                String requestId = params.getString("requestId");
                JSONObject detail = requestIdToDetail.get(requestId);
                if (detail == null) {
                    LOG.log(Level.WARNING, "no matching requestWillBeSent found for: " + notification.toJSONString());
                    // spurious first events?
                    continue;
                }

                if (Network.dataReceived.equals(method)) {
                    int encodedDataLength = params.getInt("encodedDataLength");
                    detail.put("encodedDataLength", detail.getInt("encodedDataLength") + encodedDataLength);
                } else if (Network.loadingFinished.equals(method)) {
                    if (params.has("encodedDataLength")) {
                        // some chromedriver versions don't have encodedDataLength in loadingFinished
                        // if there, check that matches the one in dataReceived
                        int finishedEncodedDataLength = params.getInt("encodedDataLength");
                        int encodedDataLength = detail.getInt("encodedDataLength");
                        if (finishedEncodedDataLength != encodedDataLength) {
                            LOG.log(Level.WARNING, "encodedDataLength doesn't match: " + finishedEncodedDataLength
                                    + " (from loadingFinished) != " + encodedDataLength + " (from dataReceived)");
                        }
                    }
                    numRequests++;
                    totalEncodedDataLength += detail.getInt("encodedDataLength");
                    details.put(detail);
                    requestIdToDetail.remove(requestId);
                } else if (Network.loadingFailed.equals(method)) {
                    // count also pages that fail to load
                    detail.put("loadingFailed", "true");
                    String errorText = params.has("errorText") ? params.getString("errorText") : null;
                    if (errorText != null && errorText.trim().length() > 0) {
                        detail.put("errorText", errorText);
                    }
                    numRequests++;
                    details.put(detail);
                    requestIdToDetail.remove(requestId);
                }
            } catch (Exception e) {
                LOG.log(Level.WARNING, notification.toJSONString(), e);
            }
        }

        // count also request that don't have a matching loadingFinished/Failed
        // (the final aura POST fails in this category)
        for (String requestId : requestIdToDetail.keySet()) {
            JSONObject detail = requestIdToDetail.get(requestId);
            LOG.log(Level.INFO, "no matching loadingFinished/Failed found for: " + detail.toString());
            numRequests++;
            details.put(detail);
        }

        PerfMetric numRequestsMetric = new PerfMetric("Network.numRequests", numRequests);
        PerfMetric encodedDataLengthMetric = new PerfMetric("Network.encodedDataLength", totalEncodedDataLength,
                "bytes");
        numRequestsMetric.setDetails(details);
        encodedDataLengthMetric.setDetails(details);

        return Lists.newArrayList(numRequestsMetric, encodedDataLengthMetric);
    }

    // dev tools log

    public List<JSONObject> getDevToolsLog() {
        List<JSONObject> devToolsLog = Lists.newArrayList();
        for (RDPNotification notification : notifications) {
            if (notification.isTimelineEvent()) {
                devToolsLog.add(notification.getTimelineEvent());
            }
        }
        return devToolsLog;
    }

    /**
     * @return the log between our timeline marks only
     */
    public List<JSONObject> getFilteredDevToolsLog() {
        List<JSONObject> devToolsLog = Lists.newArrayList();
        for (RDPNotification notification : filteredNotifications) {
            if (notification.isTimelineEvent()) {
                devToolsLog.add(notification.getTimelineEvent());
            }
        }
        return devToolsLog;
    }
}
TOP

Related Classes of org.auraframework.test.perf.rdp.RDPAnalyzer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.