HardwareDescriptionFactory.java 9.1 KB
Newer Older
1
/***********************************************************************************************************************
2
 * Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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 eu.stratosphere.nephele.instance;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
19
import java.io.InputStreamReader;
20 21 22 23 24 25
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

26 27 28
import eu.stratosphere.configuration.ConfigConstants;
import eu.stratosphere.configuration.GlobalConfiguration;
import eu.stratosphere.util.OperatingSystem;
29

30
/**
31 32 33
 * A factory to construct {@link HardwareDescription} objects. In particular,
 * the factory can automatically generate a {@link HardwareDescription} object
 * from the system it is executed on.
34 35 36 37 38 39 40 41
 * <p>
 * This class is thread-safe.
 */
public class HardwareDescriptionFactory {

	/**
	 * The log object used to report errors.
	 */
42
	private static final Log LOG = LogFactory.getLog(HardwareDescriptionFactory.class);
43

44 45 46 47 48 49
	/**
	 * The path to the interface to extract memory information under Linux.
	 */
	private static final String LINUX_MEMORY_INFO_PATH = "/proc/meminfo";

	/**
50 51
	 * The regular expression used to extract the size of the physical memory
	 * under Linux.
52
	 */
53
	private static final Pattern LINUX_MEMORY_REGEX = Pattern.compile("^MemTotal:\\s*(\\d+)\\s+kB$");
54
	
55 56 57
	/**
	 * Private constructor, so class cannot be instantiated.
	 */
58
	private HardwareDescriptionFactory() {}
59

60
	
61 62 63
	/**
	 * Extracts a hardware description object from the system.
	 * 
64 65
	 * @return the hardware description object or <code>null</code> if at least
	 *         one value for the hardware description cannot be determined
66 67
	 */
	public static HardwareDescription extractFromSystem() {
68
		int numberOfCPUCores = Runtime.getRuntime().availableProcessors();
69

70
		long sizeOfPhysicalMemory = getSizeOfPhysicalMemory();
71
		if (sizeOfPhysicalMemory < 0) {
72
			sizeOfPhysicalMemory = 1;
73 74
		}

75
		long sizeOfFreeMemory = getSizeOfFreeMemory();
76

77
		return new HardwareDescription(numberOfCPUCores, sizeOfPhysicalMemory, sizeOfFreeMemory);
78 79 80 81 82 83
	}

	/**
	 * Constructs a new hardware description object.
	 * 
	 * @param numberOfCPUCores
84 85
	 *        the number of CPU cores available to the JVM on the compute
	 *        node
86
	 * @param sizeOfPhysicalMemory
87 88
	 *        the size of physical memory in bytes available on the compute
	 *        node
89
	 * @param sizeOfFreeMemory
90 91
	 *        the size of free memory in bytes available to the JVM on the
	 *        compute node
92 93
	 * @return the hardware description object
	 */
94 95
	public static HardwareDescription construct(int numberOfCPUCores,long sizeOfPhysicalMemory, long sizeOfFreeMemory) {
		return new HardwareDescription(numberOfCPUCores, sizeOfPhysicalMemory, sizeOfFreeMemory);
96 97 98 99 100
	}

	/**
	 * Returns the size of free memory in bytes available to the JVM.
	 * 
101 102
	 * @return the size of the free memory in bytes available to the JVM or <code>-1</code> if the size cannot be
	 *         determined
103 104
	 */
	private static long getSizeOfFreeMemory() {
105 106 107
		float fractionToUse = GlobalConfiguration.getFloat(
			ConfigConstants.TASK_MANAGER_MEMORY_FRACTION_KEY, ConfigConstants.DEFAULT_MEMORY_MANAGER_MEMORY_FRACTION);
		
108
		Runtime r = Runtime.getRuntime();
109
		return (long) (fractionToUse * (r.maxMemory() - r.totalMemory() + r.freeMemory()));
110
	}
111

112 113 114
	/**
	 * Returns the size of the physical memory in bytes.
	 * 
115 116
	 * @return the size of the physical memory in bytes or <code>-1</code> if
	 *         the size could not be determined
117 118
	 */
	private static long getSizeOfPhysicalMemory() {
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
		switch (OperatingSystem.getCurrentOperatingSystem()) {
			case LINUX:
				return getSizeOfPhysicalMemoryForLinux();
				
			case WINDOWS:
				return getSizeOfPhysicalMemoryForWindows();
				
			case MAC_OS:
				return getSizeOfPhysicalMemoryForMac();
				
			case FREE_BSD:
				return getSizeOfPhysicalMemoryForFreeBSD();
				
			case UNKNOWN:
				LOG.error("Cannot determine size of physical memory for unknown operating system");
				return -1;
				
			default:
				LOG.error("Unrecognized OS");
				return -1;
139 140 141 142
		}
	}

	/**
143 144
	 * Returns the size of the physical memory in bytes on a Linux-based
	 * operating system.
145
	 * 
146 147
	 * @return the size of the physical memory in bytes or <code>-1</code> if
	 *         the size could not be determined
148
	 */
149
	@SuppressWarnings("resource")
150 151 152
	private static long getSizeOfPhysicalMemoryForLinux() {
		BufferedReader lineReader = null;
		try {
153
			lineReader = new BufferedReader(new FileReader(LINUX_MEMORY_INFO_PATH));
154

155 156 157
			String line = null;
			while ((line = lineReader.readLine()) != null) {
				Matcher matcher = LINUX_MEMORY_REGEX.matcher(line);
158
				if (matcher.matches()) {
159 160
					String totalMemory = matcher.group(1);
					return Long.parseLong(totalMemory) * 1024L; // Convert from kilobyte to byte
161 162
				}
			}
163 164 165 166 167 168 169 170 171 172 173 174 175 176
			
			// expected line did not come
			LOG.error("Cannot determine the size of the physical memory using '/proc/meminfo'. Unexpected format.");
			return -1;
		}
		catch (NumberFormatException e) {
			LOG.error("Cannot determine the size of the physical memory using '/proc/meminfo'. Unexpected format.");
			return -1;
		}
		catch (IOException e) {
			LOG.error("Cannot determine the size of the physical memory using '/proc/meminfo': " + e.getMessage(), e);
			return -1;
		}
		finally {
177 178 179 180 181
			// Make sure we always close the file handle
			try {
				if (lineReader != null) {
					lineReader.close();
				}
182
			} catch (Throwable t) {}
183 184
		}
	}
185

186
	/**
187 188
	 * Returns the size of the physical memory in bytes on a Mac OS-based
	 * operating system
189
	 * 
190 191
	 * @return the size of the physical memory in bytes or <code>-1</code> if
	 *         the size could not be determined
192 193 194
	 */
	private static long getSizeOfPhysicalMemoryForMac() {

195 196
		BufferedReader bi = null;

197
		try {
198
			Process proc = Runtime.getRuntime().exec("sysctl hw.memsize");
199

200 201
			bi = new BufferedReader(
					new InputStreamReader(proc.getInputStream()));
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

			String line;

			while ((line = bi.readLine()) != null) {
				if (line.startsWith("hw.memsize")) {
					long memsize = Long.parseLong(line.split(":")[1].trim());
					bi.close();
					proc.destroy();
					return memsize;
				}
			}

		} catch (Exception e) {
			LOG.error(e);
			return -1;
217 218 219 220 221 222 223
		} finally {
			if (bi != null) {
				try {
					bi.close();
				} catch (IOException ioe) {
				}
			}
224 225 226
		}
		return -1;
	}
227

228 229 230
	/**
	 * Returns the size of the physical memory in bytes on FreeBSD.
	 * 
231 232
	 * @return the size of the physical memory in bytes or <code>-1</code> if
	 *         the size could not be determined
233 234 235 236 237 238
	 */
	private static long getSizeOfPhysicalMemoryForFreeBSD() {
		BufferedReader bi = null;
		try {
			Process proc = Runtime.getRuntime().exec("sysctl hw.physmem");

239
			bi = new BufferedReader(new InputStreamReader(proc.getInputStream()));
240 241 242 243 244 245 246 247 248 249 250

			String line;

			while ((line = bi.readLine()) != null) {
				if (line.startsWith("hw.physmem")) {
					long memsize = Long.parseLong(line.split(":")[1].trim());
					bi.close();
					proc.destroy();
					return memsize;
				}
			}
251 252
			
			LOG.error("Cannot determine the size of the physical memory using 'sysctl hw.physmem'.");
253
			return -1;
254 255 256 257 258 259
		}
		catch (Exception e) {
			LOG.error("Cannot determine the size of the physical memory using 'sysctl hw.physmem': " + e.getMessage(), e);
			return -1;
		}
		finally {
260 261 262 263 264 265 266 267
			if (bi != null) {
				try {
					bi.close();
				} catch (IOException ioe) {
				}
			}
		}
	}
268 269 270 271 272 273 274

	/**
	 * Returns the size of the physical memory in bytes on Windows.
	 * 
	 * @return the size of the physical memory in bytes or <code>-1</code> if
	 *         the size could not be determined
	 */
275 276 277 278
	private static long getSizeOfPhysicalMemoryForWindows() {
		BufferedReader bi = null;
		try {
			Process proc = Runtime.getRuntime().exec("wmic memorychip get capacity");
279

280
			bi = new BufferedReader(new InputStreamReader(proc.getInputStream()));
281 282 283 284 285

			String line = bi.readLine();
			if (line == null) {
				return -1L;
			}
286

287 288 289 290
			if (!line.startsWith("Capacity")) {
				return -1L;
			}

291
			long sizeOfPhyiscalMemory = 0L;
292 293 294 295 296 297 298 299
			while ((line = bi.readLine()) != null) {
				if (line.isEmpty()) {
					continue;
				}

				line = line.replaceAll(" ", "");
				sizeOfPhyiscalMemory += Long.parseLong(line);
			}
300 301 302 303
			return sizeOfPhyiscalMemory;
		}
		catch (Exception e) {
			LOG.error("Cannot determine the size of the physical memory using 'wmic memorychip': " + e.getMessage(), e);
304
			return -1L;
305 306
		}
		finally {
307 308 309
			if (bi != null) {
				try {
					bi.close();
310
				} catch (Throwable t) {}
311
			}
312 313
		}
	}
314
}