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.
343 lines
8.5 KiB
343 lines
8.5 KiB
1 month ago
|
# LogModelGuess 方法比较分析
|
||
|
|
||
|
## 概述
|
||
|
|
||
|
本文档详细比较了 `LTEClient` 中的 `LogModelGuess` 方法和 JavaScript 版本 `client.js` 中的 `logModelGuess` 方法,分析它们的相似性和差异。
|
||
|
|
||
|
## JavaScript 版本实现
|
||
|
|
||
|
```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# 版本实现
|
||
|
|
||
|
```csharp
|
||
|
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 版本:**
|
||
|
```javascript
|
||
|
// 直接访问 log.layer
|
||
|
modelGuess[log.layer] = true;
|
||
|
|
||
|
// 使用 layerConfig[l].dir 获取方向配置
|
||
|
var dir = layerConfig[l].dir;
|
||
|
```
|
||
|
|
||
|
**C# 版本:**
|
||
|
```csharp
|
||
|
// 需要从 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 版本:**
|
||
|
```javascript
|
||
|
// 直接检查 dir[m] 是否存在
|
||
|
if (!dir[m]) {
|
||
|
var idx = mlist.indexOf(m);
|
||
|
if (idx >= 0)
|
||
|
mlist.splice(idx, 1);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
**C# 版本:**
|
||
|
```csharp
|
||
|
// 使用 RemoveAll 方法批量移除
|
||
|
availableModels.RemoveAll(model => !layerDir.ContainsKey(model));
|
||
|
```
|
||
|
|
||
|
#### 4. **设置模型的条件**
|
||
|
|
||
|
**JavaScript 版本:**
|
||
|
```javascript
|
||
|
if (mlist.length > 0) {
|
||
|
this.setModel(mlist); // 传递整个列表
|
||
|
}
|
||
|
```
|
||
|
|
||
|
**C# 版本:**
|
||
|
```csharp
|
||
|
if (availableModels.Count > 0 && availableModels.Count < modelList.Count)
|
||
|
{
|
||
|
SetModel(availableModels[0]); // 只传递第一个模型
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 🔧 **需要修复的问题**
|
||
|
|
||
|
#### 1. **层配置集成**
|
||
|
|
||
|
C# 版本应该从 `LogsManager` 获取层配置,而不是硬编码:
|
||
|
|
||
|
```csharp
|
||
|
// 当前实现
|
||
|
private Dictionary<string, object> GetLayerConfig()
|
||
|
{
|
||
|
// 硬编码配置
|
||
|
return new Dictionary<string, object> { ... };
|
||
|
}
|
||
|
|
||
|
// 应该改为
|
||
|
private Dictionary<string, object> GetLayerConfig()
|
||
|
{
|
||
|
return _lteLogs.GetLayerConfig(); // 从 LogsManager 获取
|
||
|
}
|
||
|
```
|
||
|
|
||
|
#### 2. **方向配置处理**
|
||
|
|
||
|
需要实现与 JavaScript 版本相同的方向配置结构:
|
||
|
|
||
|
```csharp
|
||
|
// 当前实现使用 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# 版本应该也支持:
|
||
|
|
||
|
```csharp
|
||
|
// 当前实现
|
||
|
SetModel(availableModels[0]);
|
||
|
|
||
|
// 应该改为
|
||
|
if (availableModels.Count == 1)
|
||
|
{
|
||
|
SetModel(availableModels[0]);
|
||
|
}
|
||
|
else if (availableModels.Count > 1)
|
||
|
{
|
||
|
// 支持模型列表,让 SetModel 处理
|
||
|
SetModel(string.Join(",", availableModels));
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## 建议的改进
|
||
|
|
||
|
### 1. **集成 LogsManager**
|
||
|
|
||
|
```csharp
|
||
|
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. **添加单元测试**
|
||
|
|
||
|
```csharp
|
||
|
[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 版本更加一致。
|