Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Clients.Hive.Slave/3.3/Manager/ConfigManager.cs @ 12236

Last change on this file since 12236 was 12236, checked in by ascheibe, 8 years ago

#2356 select NICs more careful for generating slave UIDs

File size: 9.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Diagnostics;
25using System.Linq;
26using System.Management;
27using System.Net.NetworkInformation;
28using HeuristicLab.Clients.Hive.SlaveCore.Properties;
29
30
31namespace HeuristicLab.Clients.Hive.SlaveCore {
32  /// <summary>
33  /// accesses the server and sends his data (uuid, uptimes, hardware config)
34  /// </summary>
35  public class ConfigManager {
36    private static ConfigManager instance = null;
37    private const string vmwareNameString = "VMware";
38    private const string virtualboxNameString = "VirtualBox";
39    private const int macLength = 12;
40
41    public static ConfigManager Instance {
42      get { return instance; }
43      set { instance = value; }
44    }
45
46    /// <summary>
47    /// if Asleep is true, the Slave won't accept any new jobs
48    /// </summary>
49    public bool Asleep { get; set; }
50    private TaskManager jobManager;
51    private Slave slave;
52    private PerformanceCounter cpuCounter;
53    private PerformanceCounter memCounter;
54
55    /// <summary>
56    /// Constructor for the singleton, must recover Guid, Calendar, ...
57    /// </summary>
58    public ConfigManager(TaskManager jobManager) {
59      this.jobManager = jobManager;
60      cpuCounter = new PerformanceCounter();
61      cpuCounter.CategoryName = "Processor";
62      cpuCounter.CounterName = "% Processor Time";
63      cpuCounter.InstanceName = "_Total";
64      memCounter = new PerformanceCounter("Memory", "Available Bytes", true);
65
66      Asleep = false;
67      slave = new Slave();
68      slave.Id = GetUniqueMachineId();
69      slave.Name = Environment.MachineName;
70      if (Settings.Default.NrOfCoresToScavenge < 1 || Settings.Default.NrOfCoresToScavenge > Environment.ProcessorCount) {
71        slave.Cores = Environment.ProcessorCount;
72      } else {
73        slave.Cores = Settings.Default.NrOfCoresToScavenge;
74      }
75      slave.Memory = GetPhysicalMemory();
76      slave.CpuArchitecture = Environment.Is64BitOperatingSystem ? CpuArchitecture.x64 : CpuArchitecture.x86;
77      slave.OperatingSystem = Environment.OSVersion.VersionString;
78      slave.CpuSpeed = GetCpuSpeed();
79      slave.IsDisposable = true;
80
81      UpdateSlaveInfo();
82    }
83
84    private void UpdateSlaveInfo() {
85      if (slave != null) {
86        slave.FreeMemory = GetFreeMemory();
87        slave.HbInterval = (int)Settings.Default.HeartbeatInterval.TotalSeconds;
88      }
89    }
90
91    /// <summary>
92    /// Get all the Information about the client
93    /// </summary>
94    /// <returns>the ClientInfo object</returns>
95    public Slave GetClientInfo() {
96      UpdateSlaveInfo();
97      return slave;
98    }
99
100    public int GetFreeCores() {
101      return slave.Cores.HasValue ? slave.Cores.Value - SlaveStatusInfo.UsedCores : 0;
102    }
103
104    /// <summary>
105    /// collects and returns information that get displayed by the Client Console
106    /// </summary>
107    /// <returns></returns>
108    public StatusCommons GetStatusForClientConsole() {
109      StatusCommons st = new StatusCommons();
110      st.ClientGuid = slave.Id;
111
112      st.Status = WcfService.Instance.ConnState;
113      st.ConnectedSince = WcfService.Instance.ConnectedSince;
114
115      st.TotalCores = slave.Cores.HasValue ? slave.Cores.Value : 0;
116      st.FreeCores = GetFreeCores();
117      st.Asleep = this.Asleep;
118
119      st.JobsStarted = SlaveStatusInfo.TasksStarted;
120      st.JobsAborted = SlaveStatusInfo.TasksAborted;
121      st.JobsFinished = SlaveStatusInfo.TasksFinished;
122      st.JobsFetched = SlaveStatusInfo.TasksFetched;
123      st.JobsFailed = SlaveStatusInfo.TasksFailed;
124
125      st.Jobs = jobManager.GetExecutionTimes().Select(x => new TaskStatus { TaskId = x.Key, ExecutionTime = x.Value }).ToList();
126
127      return st;
128    }
129
130    public Dictionary<Guid, TimeSpan> GetExecutionTimeOfAllJobs() {
131      Dictionary<Guid, TimeSpan> prog = new Dictionary<Guid, TimeSpan>();
132      try {
133        prog = jobManager.GetExecutionTimes();
134      }
135      catch (Exception ex) {
136        SlaveClientCom.Instance.LogMessage(string.Format("Exception was thrown while trying to get execution times: {0}", ex.Message));
137      }
138      return prog;
139    }
140
141    public static Guid GetUniqueMachineId() {
142      Guid id;
143      try {
144        id = GetUniqueMachineIdFromMac();
145      }
146      catch {
147        // fallback if something goes wrong...       
148        id = new Guid(Environment.MachineName.GetHashCode(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
149      }
150      return id;
151    }
152
153    /// <summary>
154    /// returns total physical memory of the machine in MB
155    /// </summary>
156    private static int? GetPhysicalMemory() {
157      long? res = GetWMIValue("Win32_ComputerSystem", "TotalPhysicalMemory");
158      if (res != null)
159        return (int)(res / 1024 / 1024);
160      else
161        return null;
162    }
163
164    /// <summary>
165    /// returns CPU frequence of the machine in Mhz
166    /// </summary>
167    private static int? GetCpuSpeed() {
168      return (int)GetWMIValue("Win32_Processor", "MaxClockSpeed");
169    }
170
171    /// <summary>
172    /// Generate a guid based on mac address of the first found nic (yes, mac addresses are not unique...)
173    /// and the machine name.
174    /// Format:
175    ///
176    ///  D1      D2  D3  Res.   D4
177    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178    /// |n a m e|0 0|0 0|0 0 mac address|
179    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
180    ///
181    /// The mac address is saved in the last 48 bits of the Data 4 segment
182    /// of the guid (first 2 bytes of Data 4 are reserved).
183    /// D1 contains the hash of the machinename.
184    /// </summary>   
185    private static Guid GetUniqueMachineIdFromMac() {
186      //try to get a real network interface, not a virtual one
187      NetworkInterface validNic = NetworkInterface.GetAllNetworkInterfaces()
188                      .FirstOrDefault(x =>
189                                  !x.Name.Contains(vmwareNameString) &&
190                                  !x.Name.Contains(virtualboxNameString) &&
191                                  (x.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
192                                   x.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet));
193
194      if (validNic == default(NetworkInterface)) {
195        validNic = NetworkInterface.GetAllNetworkInterfaces().First();
196      }
197
198      string addr = validNic.GetPhysicalAddress().ToString();
199      if (addr.Length != macLength) {
200        throw new Exception("Error generating slave UID: MAC address has to have " + macLength + " digits. Actual MAC address is: " + addr);
201      }
202
203      byte[] b = new byte[8];
204      int j = 2;
205      for (int i = 0; i < macLength; i += 2) {
206        b[j++] = (byte)((ParseNybble(addr[i]) << 4) | ParseNybble(addr[i + 1]));
207      }
208      // also get machine name and save it to the first 4 bytes               
209      Guid guid = new Guid(Environment.MachineName.GetHashCode(), 0, 0, b);
210      return guid;
211    }
212
213    /// <summary>
214    /// return numeric value of a single hex-char
215    /// (see: http://stackoverflow.com/questions/854012/how-to-convert-hex-to-a-byte-array)
216    /// </summary>   
217    static int ParseNybble(char c) {
218      if (c >= '0' && c <= '9') {
219        return c - '0';
220      }
221      if (c >= 'A' && c <= 'F') {
222        return c - 'A' + 10;
223      }
224      if (c >= 'a' && c <= 'f') {
225        return c - 'a' + 10;
226      }
227      throw new ArgumentException("Invalid hex digit: " + c);
228    }
229
230    private static long? GetWMIValue(string clazz, string property) {
231      ManagementClass mgtClass = new ManagementClass(clazz);
232      ManagementObjectCollection mgtCol = mgtClass.GetInstances();
233
234      foreach (ManagementObject mgtObj in mgtCol) {
235        foreach (var prop in mgtObj.Properties) {
236          if (prop.Value != null && prop.Name == property) {
237            try {
238              return long.Parse(prop.Value.ToString());
239            }
240            catch {
241              return null;
242            }
243          }
244        }
245      }
246      return null;
247    }
248
249    /// <summary>
250    /// returns free memory of machine in MB
251    /// </summary>   
252    public int GetFreeMemory() {
253      int mb = 0;
254
255      try {
256        mb = (int)(memCounter.NextValue() / 1024 / 1024);
257      }
258      catch { }
259      return mb;
260    }
261
262    public float GetCpuUtilization() {
263      float cpuVal = 0.0F;
264
265      try {
266        return cpuCounter.NextValue();
267      }
268      catch { }
269      return cpuVal;
270    }
271  }
272}
Note: See TracBrowser for help on using the repository browser.