You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

8.5 KiB

LogModelGuess 方法比较分析

概述

本文档详细比较了 LTEClient 中的 LogModelGuess 方法和 JavaScript 版本 client.js 中的 logModelGuess 方法,分析它们的相似性和差异。

JavaScript 版本实现

logModelGuess: function (logs) {
    var modelGuess = this.modelGuess;
    if (modelGuess) {
        for (var i = 0; i < logs.length; i++) {
            var log = logs[i];
            modelGuess[log.layer] = true;
        }

        var mlist = modelList.concat(); // Duplicate

        for (var l in layerConfig) {
            if (!modelGuess[l]) continue;

            var dir = layerConfig[l].dir;
            for (var j = 0; j < modelList.length; j++) {
                var m = modelList[j];
                if (!dir[m]) {
                    var idx = mlist.indexOf(m);
                    if (idx >= 0)
                        mlist.splice(idx, 1);
                }
            }
            if (mlist.length < 2)
                break;
        }

        if (mlist.length > 0) {
            this.setModel(mlist);
            this.modelGuess = null;
        } else {
            // XXX: parse logs later ?
        }
    }
}

C# 版本实现

public void LogModelGuess(List<Dictionary<string, object>> logs)
{
    var modelGuess = _modelGuess;
    if (modelGuess == null)
        return;

    // 标记所有出现的层
    foreach (var log in logs)
    {
        if (log.TryGetValue("layer", out var layer) && layer is string layerStr)
        {
            modelGuess[layerStr] = true;
        }
    }

    // 尝试根据层配置确定模型
    var modelList = new List<string> { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
    var availableModels = new List<string>(modelList);

    // 根据层配置过滤模型
    foreach (var layer in modelGuess.Keys)
    {
        if (!modelGuess[layer]) continue;

        var layerConfig = GetLayerConfig();
        if (layerConfig.TryGetValue(layer, out var config))
        {
            // 这里应该检查层的方向配置来过滤模型
            // 暂时简化处理
            var layerDir = GetLayerDirection(layer);
            if (layerDir != null)
            {
                // 移除不支持的模型
                availableModels.RemoveAll(model => !layerDir.ContainsKey(model));
            }
        }

        // 如果只剩下一个模型,直接设置
        if (availableModels.Count <= 1)
            break;
    }

    // 如果找到了合适的模型,设置它
    if (availableModels.Count > 0 && availableModels.Count < modelList.Count)
    {
        SetModel(availableModels[0]);
        _modelGuess = null; // 清除猜测字典
    }
}

详细比较分析

相似之处

  1. 基本逻辑相同

    • 都检查 modelGuess 是否存在
    • 都遍历日志标记出现的层
    • 都使用层配置来过滤模型
    • 都清除 modelGuess 字典
  2. 模型列表一致

    • 都使用相同的模型列表:["RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR"]
  3. 核心算法相似

    • 都基于层配置进行模型过滤
    • 都支持提前退出(当模型数量足够少时)

主要差异

1. 数据结构差异

JavaScript 版本:

// 直接访问 log.layer
modelGuess[log.layer] = true;

// 使用 layerConfig[l].dir 获取方向配置
var dir = layerConfig[l].dir;

C# 版本:

// 需要从 Dictionary 中提取 layer
if (log.TryGetValue("layer", out var layer) && layer is string layerStr)
{
    modelGuess[layerStr] = true;
}

// 使用单独的 GetLayerDirection 方法
var layerDir = GetLayerDirection(layer);

2. 层配置处理

JavaScript 版本:

  • 直接使用全局的 layerConfig 对象
  • 每个层配置包含 dir 属性,直接映射模型到方向值

C# 版本:

  • 使用 GetLayerConfig() 方法返回基本配置
  • 使用 GetLayerDirection() 方法返回方向配置
  • 配置是硬编码的,而不是从 LogsManager 获取

3. 模型过滤逻辑

JavaScript 版本:

// 直接检查 dir[m] 是否存在
if (!dir[m]) {
    var idx = mlist.indexOf(m);
    if (idx >= 0)
        mlist.splice(idx, 1);
}

C# 版本:

// 使用 RemoveAll 方法批量移除
availableModels.RemoveAll(model => !layerDir.ContainsKey(model));

4. 设置模型的条件

JavaScript 版本:

if (mlist.length > 0) {
    this.setModel(mlist);  // 传递整个列表
}

C# 版本:

if (availableModels.Count > 0 && availableModels.Count < modelList.Count)
{
    SetModel(availableModels[0]);  // 只传递第一个模型
}

🔧 需要修复的问题

1. 层配置集成

C# 版本应该从 LogsManager 获取层配置,而不是硬编码:

// 当前实现
private Dictionary<string, object> GetLayerConfig()
{
    // 硬编码配置
    return new Dictionary<string, object> { ... };
}

// 应该改为
private Dictionary<string, object> GetLayerConfig()
{
    return _lteLogs.GetLayerConfig();  // 从 LogsManager 获取
}

2. 方向配置处理

需要实现与 JavaScript 版本相同的方向配置结构:

// 当前实现使用 switch 表达式
private Dictionary<string, int>? GetLayerDirection(string layer)

// 应该改为直接访问层配置的 dir 属性
private Dictionary<string, int>? GetLayerDirection(string layer)
{
    var layerConfig = _lteLogs.GetLayerConfig();
    if (layerConfig.TryGetValue(layer, out var config))
    {
        return config.Dir;  // 直接返回方向配置
    }
    return null;
}

3. 模型设置逻辑

JavaScript 版本支持传递模型列表,C# 版本应该也支持:

// 当前实现
SetModel(availableModels[0]);

// 应该改为
if (availableModels.Count == 1)
{
    SetModel(availableModels[0]);
}
else if (availableModels.Count > 1)
{
    // 支持模型列表,让 SetModel 处理
    SetModel(string.Join(",", availableModels));
}

建议的改进

1. 集成 LogsManager

public void LogModelGuess(List<Dictionary<string, object>> logs)
{
    var modelGuess = _modelGuess;
    if (modelGuess == null)
        return;

    // 标记所有出现的层
    foreach (var log in logs)
    {
        if (log.TryGetValue("layer", out var layer) && layer is string layerStr)
        {
            modelGuess[layerStr] = true;
        }
    }

    // 从 LogsManager 获取层配置
    var layerConfig = _lteLogs.GetLayerConfig();
    var modelList = new List<string> { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
    var availableModels = new List<string>(modelList);

    // 根据层配置过滤模型
    foreach (var layer in modelGuess.Keys)
    {
        if (!modelGuess[layer]) continue;

        if (layerConfig.TryGetValue(layer, out var config))
        {
            var dir = config.Dir;  // 直接获取方向配置
            if (dir != null)
            {
                // 移除不支持的模型
                availableModels.RemoveAll(model => !dir.ContainsKey(model));
            }
        }

        if (availableModels.Count <= 1)
            break;
    }

    // 设置模型
    if (availableModels.Count > 0)
    {
        if (availableModels.Count == 1)
        {
            SetModel(availableModels[0]);
        }
        else
        {
            // 支持多个模型的情况
            SetModel(string.Join(",", availableModels));
        }
        _modelGuess = null;
    }
}

2. 添加单元测试

[Test]
public void LogModelGuess_WithPhyAndRrcLogs_ShouldSetEnbModel()
{
    // Arrange
    var client = new LTEClient("test", logsManager);
    client.LogModelGuessInit();
    
    var logs = new List<Dictionary<string, object>>
    {
        new Dictionary<string, object> { { "layer", "PHY" } },
        new Dictionary<string, object> { { "layer", "RRC" } }
    };

    // Act
    client.LogModelGuess(logs);

    // Assert
    Assert.AreEqual("ENB", client.Config.Model);
}

总结

虽然 C# 版本和 JavaScript 版本的基本逻辑相似,但存在一些重要的差异:

  1. 数据结构处理:C# 版本需要处理 Dictionary 类型安全
  2. 配置管理:C# 版本应该集成 LogsManager 而不是硬编码
  3. 模型设置:C# 版本应该支持模型列表传递
  4. 错误处理:C# 版本有更好的类型安全和空值检查

建议按照上述改进建议来完善 C# 版本,使其与 JavaScript 版本更加一致。