/*
* Tencent is pleased to support the open source community by making
* Tencent GT (Version 2.4 and subsequent versions) available.
*
* Notwithstanding anything to the contrary herein, any previous version
* of Tencent GT shall not be subject to the license hereunder.
* All right, title, and interest, including all intellectual property rights,
* in and to the previous version of Tencent GT (including any and all copies thereof)
* shall be owned and retained by Tencent and subject to the license under the
* Tencent GT End User License Agreement (http://gt.qq.com/wp-content/EULA_EN.html).
*
* Copyright (C) 2015 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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 com.tencent.wstt.gt.log;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.tencent.wstt.gt.Functions;
import com.tencent.wstt.gt.api.utils.Env;
import com.tencent.wstt.gt.ui.model.GroupTimeEntry;
import com.tencent.wstt.gt.ui.model.TagTimeEntry;
import com.tencent.wstt.gt.utils.GTUtils;
public class LogTimeController {
private LinkedHashMap<String, GroupTimeEntry> groupMap =
new LinkedHashMap<String, GroupTimeEntry>();
private boolean started = false;
// TODO 为提高性能引入的变量,在第二期应该尽量优化掉
private boolean startedOnceUntilNotClear = false;
private Lock lock; // 结合界面的实际逻辑,用普通的锁即可,不需要读写锁
public LogTimeController()
{
if (GTUtils.isSDCardExist() && !Env.ROOT_TIME_FOLDER.exists())
{
Env.ROOT_TIME_FOLDER.mkdirs();
}
// started = GTPref.getGTPref().getBoolean(GTPref.PERF_MASTER_SWITCH, started);
lock = new ReentrantLock();
}
public List<GroupTimeEntry> getShowList()
{
List<GroupTimeEntry> result = new ArrayList<GroupTimeEntry>();
if (startedOnceUntilNotClear)
{
lock.lock();
result.addAll(groupMap.values());
lock.unlock();
}
return result;
}
public GroupTimeEntry getGroupTimeEntry(String name)
{
return groupMap.get(name);
}
/**
* 给详情页返回数据源,要么返回全局的统计,要么返回区分线程的统计
* @param tid
* @param parentName
* @param name
* @return
*/
public TagTimeEntry getTagTimeEntry(long tid, String parentName, String name)
{
GroupTimeEntry groupTimeEntry = groupMap.get(parentName);
TagTimeEntry tagTimeEntry = null;
if (null != groupTimeEntry)
{
tagTimeEntry = groupTimeEntry.getStaticsEntry(name, tid);
}
return tagTimeEntry;
}
/**
* 记录单点的性能数据(start和end这种成对的称为双点性能数据),也按tid区分全局的还是线程的
*/
public void recordDigital(long tid, String group, String tag, long[] datas, int funcId) {
if (!started)
{
return;
}
if (null != group && null != tag)
{
GroupTimeEntry groupEntry = groupMap.get(group);
if (null == groupEntry)
{
groupEntry = new GroupTimeEntry(group);
lock.lock();
groupMap.put(group, groupEntry);
lock.unlock();
}
// 从Group中取出由tag, tid共同标示的统计对象(exKey无用)
TagTimeEntry staticsTagTimeEntry = groupEntry.getStaticsEntry(tag, tid);
if (null == staticsTagTimeEntry)
{
staticsTagTimeEntry = new TagTimeEntry(groupEntry);
staticsTagTimeEntry.setName(tag);
staticsTagTimeEntry.setTid(tid);
staticsTagTimeEntry.setFunctionId(funcId);
staticsTagTimeEntry.initChildren(datas.length - 1);
groupEntry.addStaticsEntry(staticsTagTimeEntry);
}
if (Functions.PERF_DIGITAL_MULT == funcId
|| Functions.PERF_DIGITAL_MULT_MEM == funcId)
{
TagTimeEntry[] subEntrys = staticsTagTimeEntry.getSubTagEntrys();
for (int i = 0; i < subEntrys.length; i++)
{
TagTimeEntry subEntry = subEntrys[i];
subEntry.add(datas[i]);
}
staticsTagTimeEntry.add(datas[0]); // TODO 得记录一个维度的值,否则外面UI无法展示
}
else
{
staticsTagTimeEntry.add(datas[0]);
}
}
}
/**
* 规定不区分线程的tid为0,被测程序的线程号为正数,GT控制台的线程号为负数
*/
public void startTime(long tid, String group, String tag,
int exKey, long start, int funcId) {
if (null != group && null != tag)
{
GroupTimeEntry groupEntry = groupMap.get(group);
if (null == groupEntry)
{
groupEntry = new GroupTimeEntry(group);
lock.lock();
groupMap.put(group, groupEntry);
lock.unlock();
}
// 从Group中取出由tag, tid, exKey共同标示的TagTimeEntry对象
TagTimeEntry tagEntry = groupEntry.getThreadEntry(tag, tid, exKey);
if (null == tagEntry)
{
tagEntry = new TagTimeEntry(groupEntry);
tagEntry.setName(tag);
tagEntry.setTid(tid);
tagEntry.setExkey(exKey);
/*
* funcId用的是PERF_START_TIME_GLOBAL或PERF_START_DIGITAL_GLOBAL
* 对于后面的使用只是保证UI精度,不会做其他依赖funcId的逻辑计算
*/
tagEntry.setFunctionId(funcId);
groupEntry.addEntry(tagEntry);
}
tagEntry.setLastStart(start);
}
}
public long endTime(long tid, String group, String tag,
int exKey, long end, int funcId) {
if (null != group && null != tag)
{
GroupTimeEntry groupEntry = null;
TagTimeEntry tagEntry = null;
if (null == groupMap.get(group))
{
return -1;
}
groupEntry = groupMap.get(group);
if (null == groupEntry)
{
return -1;
}
tagEntry = groupEntry.getThreadEntry(tag, tid, exKey);
if (null == tagEntry)
{
return -1;
}
if (tagEntry.getLastStart() <= 0)
{
return -1;
}
long reduce = end - tagEntry.getLastStart();
tagEntry.setLastStart(0);
if (started)
{
// 在对应的统计对象中加入差值,注意统计值是不关注exKey的
TagTimeEntry staticsTagTimeEntry = groupEntry.getStaticsEntry(tag, tid);
staticsTagTimeEntry.add(reduce);
}
return reduce;
}
return -1;
}
public void setState(boolean flag)
{
started = flag;
if (flag)
{
startedOnceUntilNotClear = true;
}
// GTPref.getGTPref().edit().putBoolean(GTPref.PERF_MASTER_SWITCH, started).commit();
if (!started)
{
for (GroupTimeEntry gte : groupMap.values())
{
for (TagTimeEntry tte : gte.entrys())
{
/*
* 后面处理注意,这个操作之后如果TagTimeEntry对象收到对应的
* 一条endTime消息,则是上次消费的,需要丢弃,
* 即在lastStart==0时,只有收到startTime消息才是开始有效的。
* 同一个线程内,不需要担心乱序、多条的问题
*/
tte.setLastStart(0);
}
}
}
}
public boolean getState()
{
return started;
}
public void clearAllCache()
{
if (started)
{
return;
}
startedOnceUntilNotClear = false;
if (null != groupMap)
{
for (GroupTimeEntry gte : groupMap.values())
{
for (TagTimeEntry tte : gte.entrys())
{
tte.clear();
}
gte.clear();
}
groupMap.clear();
}
}
public void saveAllCache(String fileName)
{
LogUtils.writeTimeLog(getShowList(), fileName);
}
public void saveCache(String fileName, TagTimeEntry tagTimeEntry)
{
// 路径的情况,直接存在指定路径
LogUtils.writeTimeDetail(tagTimeEntry, fileName);
}
}